[R] returning functions inside lapply
Duncan Murdoch
murdoch.duncan at gmail.com
Tue Apr 24 22:57:07 CEST 2012
On 12-04-24 4:22 PM, Ali Tofigh wrote:
> This has been asked before, but I just cannot figure out why lapply
> should behave this way given that R uses lazy evalution. Even after
> reading (or at least trying to read) parts of the R language
> definition.
>
>> f<- function(x) {function() {x}}
>> a<- list(f(1), f(2), f(3))
>> a[[1]]() # as expected
> [1] 1
>> a[[2]]() # as expected
> [1] 2
>> a[[3]]() # as expected
> [1] 3
>> b<- sapply(1:3, f)
>> b[[1]]() # why?
> [1] 3
>> b[[2]]() # why?
> [1] 3
>> b[[3]]() # expected, kind of...
> [1] 3
>
> Now I know that if I force the evaluation of x inside my function f,
> that the behaviour will change, i.e., b[[1]]() will return the value 1
> etc. But could some knowledgeable person please tell me how the lazy
> evaluation as implemented in R results in, what I preceive to be, a
> very strange behaviour when using lapply as above? I thought that
> lapply calls f three times and returns a list with whatever f
> returned. Is this not so?
That is so. In each case, f creates a function that looks in its
enclosing environment for the variable x to be returned.
That enclosing environment is the evaluation frame of f, where x is the
argument being passed.
But x is never used in evaluating f, so the promise to evaluate x is
never forced until you finally call one of those functions.
That means x will refer to some internal variable in lapply (which
sapply calls). You'll have 3 different promises to evaluate it, but
they all evaluate to the same value.
You will get the result you want by forcing evaluation of x in f. Then
the three promises get evaluated before the internal value gets changed.
f<- function(x) { force(x); function() {x}}
b<- sapply(1:3, f)
b[[1]]() # gives 1
You should almost always force evaluation of arguments before returning
a constructed function to avoid problems like you had.
Duncan Murdoch
More information about the R-help
mailing list