Promises in lapply / R

放肆的年华 提交于 2019-12-19 03:40:37

问题


I am not sure what the promises are doing in R

If one runs

a = lapply(seq_len(2), function(n) { function() {n}})
b = lapply(seq_len(2), function(n)  {n})

we can see that

a[[1]]() # == 2
b[[1]]   # == 1

I understand that R uses promise's object and lazily evaluates an expression in its environment, but I dont understand why the different environments created for each function would not contain their own value for n.

[[1]]
function () 
{
    n
}
<environment: 0x7f9b2416ad18>

[[2]]
function () 
{
    n
}
<environment: 0x7f9b2416ab20>

as.list(environment(a[[1]])) 
$n
[1] 2

as.list(environment(a[[2]]))
$n
[1] 2

Is it be possible to fix the semantic through the lapply function somehow ?

lapply
function (X, FUN, ...) 
{
    FUN <- match.fun(FUN)
    if (!is.vector(X) || is.object(X)) 
        X <- as.list(X)
    .Internal(lapply(X, FUN))
}
<bytecode: 0x7f9b25150f18>
<environment: namespace:base>

PS : refocused question

Edit : concretely, is it possible to write a lapply2 function that generically "forces" the argument to have uniform behaviour as in :

pl <- lapply (1:3, function(y) { force(y); function(x) pow(x,y) } )
pl <- lapply2(1:3, function(y) { function(x) pow(x,y) } )

回答1:


I find it easier to understand in this form:

f=function(n) {function() {n}}
x=1
a=f(x)
x=2
a()
[1] 2

The key part of the documentation is

When a function is called the arguments are matched and then each of the formal arguments is bound to a promise. The expression that was given for that formal argument and a pointer to the environment the function was called from are stored in the promise.

After the call a=f(x), the function argument n is bound to a promise with the name x and a pointer to the global environment .GlobalEnv.

In your lapply examples, the anonymous function function(n) { function() {n}} is called from the global environment each time. This is why every element of the list a gets the same value of n: it's coming from the global environment. I don't see how it's possible to change this behaviour by rewriting lapply.




回答2:


I posted a comment a while ago that this might be the case as of recent versions of R but here is an offical proof as well that lapply now behaves exactly like your lapply2 version, taken from the news release of R 3.2.0.

  • 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. This resolves PR#16093.


来源:https://stackoverflow.com/questions/17530725/promises-in-lapply-r

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!