Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning anonymous functions from lapply - what is going wrong?

When trying to create a list of similar functions using lapply, I find that all the functions in the list are identical and equal to what the final element should be.

Consider the following:

pow <- function(x,y) x^y
pl <- lapply(1:3,function(y) function(x) pow(x,y))
pl
[[1]]
function (x) 
pow(x, y)
<environment: 0x09ccd5f8>

[[2]]
function (x) 
pow(x, y)
<environment: 0x09ccd6bc>

[[3]]
function (x) 
pow(x, y)
<environment: 0x09ccd780>

When you try to evaluate these functions you get identical results:

pl[[1]](2)
[1] 8
pl[[2]](2)
[1] 8
pl[[3]](2)
[1] 8

What is going on here, and how can I get the result I desire (the correct functions in the list)?

like image 828
James Avatar asked Apr 01 '13 11:04

James


People also ask

What is the point of anonymous functions?

The advantage of an anonymous function is that it does not have to be stored in a separate file. This can greatly simplify programs, as often calculations are very simple and the use of anonymous functions reduces the number of code files necessary for a program.

What is the correct implementation of the anonymous function?

Anonymous functions are implemented using the Closure class. printf("Hello %s\r\n", $name); };


2 Answers

R passes promises, not the values themselves. The promise is forced when it is first evaluated, not when it is passed, and by that time the index has changed if one uses the code in the question. The code can be written as follows to force the promise at the time the outer anonymous function is called and to make it clear to the reader:

pl <- lapply(1:3, function(y) { force(y); function(x) pow(x,y) } )
like image 79
G. Grothendieck Avatar answered Oct 04 '22 01:10

G. Grothendieck


This is no longer true as of R 3.2.0!

The corresponding line in the change log reads:

Higher order functions such as the apply functions and Reduce() now force arguments to the functions they apply in order to eliminate undesirable interactions between lazy evaluation and variable capture in closures.

And indeed:

pow <- function(x,y) x^y
pl <- lapply(1:3,function(y) function(x) pow(x,y))
pl[[1]](2)
# [1] 2
pl[[2]](2)
# [1] 4
pl[[3]](2)
# [1] 8
like image 36
jhin Avatar answered Oct 04 '22 02:10

jhin