被封闭的行为困惑

时间:2013-10-13 13:04:41

标签: r

我的程序的以下简化版本捕获了混乱。

我正在尝试创建一组函数 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行之前)

这让我很困惑。我找到了thread,其中有建议使用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

问题:

  1. 为什么K的评估(如我的情况通过print(K)force(K))会改变闭包的行为?
  2. 为什么第6行?它看起来与print(K + 10)的输出相同如果 K是 vector 等于 1:5

1 个答案:

答案 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的输出,它将所有表达式的结果连接在一起。