[R] returning functions inside lapply
Ali Tofigh
alix.tofigh at gmail.com
Wed Apr 25 01:34:36 CEST 2012
Many thanks to both Duncan and Bert for clarifying this. Having looked
carefully at what you both wrote, my conclusion is the following:
in this code below
f <- function(x) {function() {x}}
b <- lapply(1:3, f)
lapply does not actually call f with the values 1, 2, and 3. Instead,
it calls f three times with the same object that, had only f used x
for something, would have evaluated to 1 in the first call and to 2 in
the second etc. but since f does not use x, the expression passed to f
is never actually evaluated until the first time one of the functions
in b is called. But at that point, that object will evaluate to 3 for
all three functions in b.
so what lapply is doing resembles:
> z <- 1; i <- f(z); z <-2; j <- f(z); z <- 3; k <- f(z); b <- list(i, j, k)
> b[[1]]()
[1] 3
> b[[2]]()
[1] 3
> b[[3]]()
[1] 3
Thanks again!
/Ali
On Tue, Apr 24, 2012 at 18:37, Duncan Murdoch <murdoch.duncan at gmail.com> wrote:
> On 12-04-24 5:13 PM, Ali Tofigh wrote:
>>
>> On Tue, Apr 24, 2012 at 16:57, Duncan Murdoch<murdoch.duncan at gmail.com>
>> wrote:
>>>>
>>>> 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.
>>
>>
>> Thank you Duncan for you reply! However, I'm not sure I understand
>> this last explanation. This is what I think you mean lapply does.
>> Pleas correct me if I'm wrong.
>>
>> 1) lapply uses the same variable name as the argument in my function
>> (in this case 'x')
>
>
> No, lapply can use any name it likes, or no name at all (e.g. just an
> expression like 1+y).
>
>
>> 2) lapply uses this 'x' variable to set up a bunch of unevaluated calls
>
>
> No, lapply calls f a bunch of times, passing this expression each time.
>
>
>> 3) finally, lapply evaluates all the calls. but at this point,
>> lapply's 'x' variable is set to the last element of the list that was
>> passed to it and all the unevaluated calls will now use this value as
>> their 'x'?
>
>
> When lapply evaluates f, it produces a function that refers to the local
> variable x in each evaluation frame. That's a different variable each time,
> but in all cases it's a promise to evaluate the expression that lapply
> passed in. So if lapply passed 1+y as the expression, x becomes a promise
> to evaluate 1+y in lapply's evaluation frame.
>
> Since you don't call any of those functions until after lapply is done, its
> evaluation frame will remain. It's hard to get to it, but each of those
> promises references it.
>
> When you finally evaluate x in one of those functions, it goes and evaluates
> 1+y in the lapply frame (or whatever the expression was). That evaluates to
> 3. It could have evaluated to 17 if lapply had done something stupid like
> setting y to 16 after calling f in the loop, but R functions never do stupid
> things, so you don't need to worry about that.
>
> Duncan Murdoch
More information about the R-help
mailing list