When I make a loop to wrap functions in a list, the last function in the input list is always used for all wrapping call.
wrapper <- function(f)function()f()
fs <- list(f = function()"call f", g = function()"call g")
ws <- list()
for(n in names(fs))
    ws[[n]] <- wrapper(fs[[n]])
ws$f()
[1] "call g"
I expected "call f" in the above code, but it returned "call g" in fact.
Could anyone explain me why this happened?
What is the sign, or in which situation I have to force evaluation to avoid the similar
Thank you very much
Finally, I figured out my own answer
There are 2 reasons why this happens: for loop does not have its own environment and wrapper does lazily evaluate its parameter f.
For the first reason: for loop uses the global environment
For the latter reason: changing wrapper to function(f){force(f); function()f()} leads to my expected result in the question.
Detailed explanation:
The loop in the question is interpreted into
for(n in names(fs)){
  tmp <- fs[[n]]
  ws[[n]] <- wrapper(tmp)
}
Because wrapper does lazily evaluate parameter f, it keeps f in its execution environment but does not keep its value. Instead, it memorizes how-to-evaluate f when need. In other word, it memorizes the pair (<environment: R_GlobalEnv>, "tmp").
Checking out the following code clears everything I said.
tmp <- f
wf <- wrapper(tmp)
tmp <- g
wf()
[1] "call g"
but
tmp <- f
wf <- wrapper(tmp)
wf()
[1] "call f"
tmp <- g
wf()
[1] "call f"
The latter code printed "call f" in the second call because f is evaluated and stored in wrapper's environment and there is no need to evaluated again (to become g)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With