我的程序的以下简化版本捕获了混乱。
我正在尝试创建一组函数 f1,f2,...,fK,...,fn 定义为 fK(x)= print(K + x) 。为此,我创建了函数工厂:
factory = function (K) {
function (x) print(K + x)
}
并使用它来创建5个函数:funcs = sapply(1:5, factory)
我将它们逐个称为相同的值: x = 10
callOnef = function (f, x) f(x)
sapply(funcs, callOnef, 10)
我预计输出为(每行一个) 11 12 13 14 15 ,但我得到(每行一个) 15 15 15 15 15 和在第6行,一行五个 15 。
当我在print(K)
的定义中插入factory
时,输出更改为(每行一个) 11 12 13 14 15 和在第6行,一排 11 12 13 14 15 。 (忽略打印(K)本身的输出,在6行之前)
force
。
因此,我将print(K)
替换为force(K)
:
factory = function (K) {
force(K)
function (x) print(K + x)
}
输出现在(每行一个) 11 12 13 14 15 和在第6行,一行 11 12 13 14 15
问题:
print(K)
或force(K)
)会改变闭包的行为?答案 0 :(得分:2)
这种奇怪的行为是R懒惰评估的结果。在需要之前,R不会评估函数的参数。相反,它创建了一个promise对象,它由表达式和环境组成。
您可以在此代码中更清楚地看到正在发生的事情:
> factory = function (K) {
+ function (x) {
+ print(K + x)
+ }
+ }
> funcs<-list()
> for(i in 1:5)
+ funcs[[i]]<-factory({cat("evaluating K:",i,"\n"); i})
>
没有打印出任何内容,这意味着尚未评估factory
调用的参数。他们仍然有义务在全球环境中评估{cat("evaluating K:",i,"\n"); i}
。由于i
现在等于5
,因此我们会遇到此行为:
> funcs[[1]](10)
evaluating K: 5
[1] 15
如果我们在全球环境中更改i
,它将影响尚未评估的承诺,但不会影响已经解决的承诺:
> i<-4
> funcs[[2]](10)
evaluating K: 4
[1] 14
> funcs[[1]](10)
[1] 15
force
更改此行为的原因是因为force
强制在当场评估承诺,因此承诺会立即变为值。
至于问题的第二部分,第6行只是sapply
的输出,它将所有表达式的结果连接在一起。