嵌套 R 函数的范围

scope of nested R function

我有一个例子,我不确定我是否理解 R 中的作用域,我也不认为它在做正确的事情。该示例由 J. Fox

从 "An R and S-PLUS Companion to Applied Regression" 修改而来
> make.power = function(p) function(x) x^p
> powers = lapply(1:3, make.power)
> lapply(powers, function(p) p(2))

我在列表中期望的是三个分别计算恒等式、平方和立方函数的函数,但它们都立方化了它们的参数。如果我不使用 lapply,它会按预期工作。

> id = make.power(1)
> square = make.power(2)
> cube = make.power(3)
> id(2)
[1] 2
> square(2)
[1] 4
> cube(2)
[1] 8

我是唯一觉得这令人惊讶或不安的人吗?有什么令人满意的理由吗?谢谢

PS: 我已经在 Google 和 SO 上进行了搜索,但是,可能由于与此问题相关的关键字的普遍性,我空手而归。

PPS:这个例子的动机是 quickcheck 包中的一个真正的错误,而不是纯粹的好奇心。我有解决该错误的方法,感谢您的关注。这是为了学习一些东西。

当然,在发布问题后,我想到了一个可以澄清问题的不同示例。

> p = 1
> id = make.power(p)
> p = 2
> square = make.power(p)
> id(2)
[1] 4

p 与隐藏在lapply 中的循环变量具有相同的作用。 p 由一个方法传递,在这种情况下看起来像对 make.power 的引用。 Make.power 不评估它,只是保留一个指向它的指针。我在正确的轨道上吗?

这解决了问题

make.power = function(p) {force(p); function(x) x^p}
powers = lapply(1:3, make.power)
lapply(powers, function(p) p(2))

此问题是函数参数作为 "promises" 传递,在实际使用之前不会对其进行评估。在这里,因为您在调用 make.power() 时从未实际使用 p,所以它保留在新创建的环境中作为指向传递给函数的变量的承诺。当您最终调用 powers() 时,最终会评估该承诺,并且 p 的最新值将来自 lapply 的最后一次迭代。因此你所有的函数都是立方的。

这里的force()强制对promise求值。这允许每个新创建的函数对 p 的特定值具有不同的引用。