嵌套R函数的范围

时间:2015-01-31 01:08:18

标签: r nested lexical-scope referential-transparency

我有一个例子,我不确定我是否理解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:这个例子是由快速检查包中的真正错误所驱动的,而不是纯粹的好奇心。我有一个bug的解决方法,感谢您的关注。这是关于学习的东西。

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

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

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

1 个答案:

答案 0 :(得分:2)

这解决了问题

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

这个问题是函数参数作为“promises”传递,直到实际使用它们才会被评估。这里,因为在调用p时你从未真正使用make.power(),所以它在新创建的环境中保留为指向传递给函数的变量的promise。当您最终调用powers()时,最终会评估该承诺,p的最新值将来自lapply的最后一次迭代。因此,你所有的功能都是立方体的。

force()强制对承诺进行评估。这允许新创建的函数对特定值p具有不同的引用。