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