用lappy/R表示的承诺
我不确定这些承诺在R里做了什么 如果有人跑用lappy/R表示的承诺,r,binding,higher-order-functions,R,Binding,Higher Order Functions,我不确定这些承诺在R里做了什么 如果有人跑 a = lapply(seq_len(2), function(n) { function() {n}}) b = lapply(seq_len(2), function(n) {n}) 我们可以看到 a[[1]]() # == 2 b[[1]] # == 1 我知道R在其环境中使用并懒散地计算表达式,但我不明白为什么为每个函数创建的不同的环境不包含它们自己的n值 [[1]] function () { n } <enviro
a = lapply(seq_len(2), function(n) { function() {n}})
b = lapply(seq_len(2), function(n) {n})
我们可以看到
a[[1]]() # == 2
b[[1]] # == 1
我知道R在其环境中使用并懒散地计算表达式,但我不明白为什么为每个函数创建的不同的环境不包含它们自己的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
[[1]]
函数()
{
N
}
[[2]]
函数()
{
N
}
as.list(环境(a[[1]]))
$n
[1] 2
as.list(环境(a[[2]]))
$n
[1] 2
是否有可能通过lappy函数以某种方式修复语义
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>
lappy
功能(X,乐趣,…)
{
乐趣我发现这种形式更容易理解:
f=function(n) {function() {n}}
x=1
a=f(x)
x=2
a()
[1] 2
文档的关键部分是
调用函数时,参数匹配,然后
形式上的论据是有承诺的
为该形式参数和指向环境的指针提供
从中调用的函数存储在promise中
在调用a=f(x)
之后,函数参数n
绑定到一个名为x
的承诺,并指向全局环境.GlobalEnv
在您的lappy
示例中,匿名函数function(n){function(){n}
每次都从全局环境调用。这就是为什么列表中的每个元素a
都获得相同的n值的原因:它来自全局环境。我不知道如何通过重写lappy来改变这种行为。我不久前发表了一条评论,认为这可能是最近版本的情况R
的版本,但这里有一个官方证据表明lappy
现在的行为与您的lapply2
版本完全相同,该版本取自
- 高阶函数,如apply函数和Reduce()现在将参数强制应用于它们应用的函数,以消除闭包中惰性求值和变量捕获之间不必要的交互。这解决了PR#16093
我有点困惑。这不是因为每个函数的环境只包含承诺,而不包含值吗?正如您在上一个问题中所解释的,在需要时才对其进行评估?现在您正在比较闭包和值。我想说这就像苹果和桔子,但是。所以我只说“不要这样做。”是的,问题不在于承诺本身,只要环境得到了充分的跟踪。我想发布一个更新-看起来R中的情况已经发生了变化,从问题开始的代码片段现在确实返回了相同的结果。我记得在Hadley Wickham的Advanced R书中看到了相同的结果,其中有一个关于dan的代码片段警告承诺的实现实际上产生了其他东西。据我所知,lapply现在可能会强制其有趣的参数,类似于您的lapply2建议。这可能就是发生的情况。但在其他语言中实现闭包似乎很奇怪。根据定义,当给定相同的参数时,函数应该始终返回相同的结果这太棒了!谢谢你提到它。然后它将更像是在闭包后保留词法范围的常规函数语言。非常成功
f=function(n) {function() {n}}
x=1
a=f(x)
x=2
a()
[1] 2