0

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

我正在尝试创建一组函数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)当我在 的定义中插入 a时factory,输出更改为(每行一个)11 12 13 14 15 第 6 行,一行11 12 13 14 15。(忽略 6 行之前的 print(K) 本身的输出)

这让我很困惑。我找到了一个有建议使用的线程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)or force(K),)会改变闭包的行为?
  2. 为什么是第 6 行?如果K 是等于1:5的向量,它看起来与 print(K + 10) 的输出相同。
4

1 回答 1

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}在全球环境中进行评估的承诺。因为inow 等于5,所以我们得到这个行为:

> funcs[[1]](10)
evaluating K: 5 
[1] 15

如果我们i在全局环境中发生变化,它会影响仍然未评估的 Promise,但不会影响已经解决的 Promise:

> i<-4
> funcs[[2]](10)
evaluating K: 4 
[1] 14
> funcs[[1]](10)
[1] 15

force改变这种行为的原因是因为force强制当场评估承诺,所以承诺立即成为一个值。

至于问题的第二部分,第 6 行只是 的输出sapply,它将所有表达式的结果连接在一起。

于 2013-10-13T13:42:33.447 回答