[R] returning functions inside lapply

Duncan Murdoch murdoch.duncan at gmail.com
Wed Apr 25 02:17:42 CEST 2012


On 12-04-24 7:34 PM, Ali Tofigh wrote:
> 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

Yes, I think that's exactly right.

Duncan Murdoch

>
> 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