[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