为什么没有''通过嵌套函数传递变量范围?

时间:2014-09-23 14:11:48

标签: r scope

在R中,如果我创建一个环境,然后使用with来评估该环境中的函数,则该函数通常可以访问变量。但是,如果我嵌套函数,由于某种原因,它们会超出范围。你能解释一下为什么会这样吗?

示例:

使用名为x

的变量创建新环境
E = new.env();
E$x = c(1,2,3)

使用with我可以打印此变量:

with(E, print(x));
#[1] 1 2 3

但是现在如果我嵌套这个功能,它就不再起作用了:

printMe = function() { print(x); }
with(E, printMe())
#Error in print(x) : object 'x' not found

我知道我可以让它再次起作用:

printMe = function(x) { print(x); }
with(E, printMe(x))
#[1] 1 2 3

但我不明白 - 如果with创建了一个环境,为什么嵌套函数可以看到x?它可以附加它:

attach(E)
printMe()
#[1] 1 2 3

我认为我只是缺少一些关于范围界定的内容,但建议的方法是什么?或者,以另一种方式提出我的问题:为什么with中的嵌套函数不能访问自由变量?

2 个答案:

答案 0 :(得分:7)

基本上,当您使用with时,您的行为与

相同
printMe = function() { print(x); }
local({
    x=1:3
    printMe()
})
# Error in print(x) : object 'x' not found

这也行不通。这与函数中如何解析自由变量有关。当你调用printMe时,它将寻找解决机箱本身的变量,然后查找定义函数的父框架(它不会查看调用函数的位置)。这里,printMe在全局环境中定义。但是,x未在全局环境中定义。如果你这样做

printMe = function() { print(x); }
x=1:3
printMe()
# [1] 1 2 3

然后xprintMe都在全局环境中定义,因此它可以正常工作。您还可以更改printMe功能

的环境
 environment(printMe) <- E
 printMe()
 # [1] 1 2 3

或在与

相同的环境中定义函数
with(E,{printMe <- function() {print(x)}; printMe()})
# [1] 1 2 3

重点是,您调用函数的环境并不重要,重要的是它们所定义的环境。

您可能需要查看有关这些属性的函数式编程的Advanced R材料。

答案 1 :(得分:4)

R is lexically scoped not dynamically scoped. printMe的环境是全球环境,因为它是在全球环境中定义的:

environment(printMe)
<environment: R_GlobalEnv>

所以当你打电话时:

with(E, printMe())

函数printMe尝试在本地查找x。它没有。然后它尝试在其环境中找到x,这是全局环境而不是 with的本地环境。它没有找到它,然后它抛出一个错误。

为了说明这一点,请注意,如果您在printMe内定义withprintMe的环境将是with的本地环境,它会找到{{} 1}}:

x

或者,您可以更改with(E,{ printMe <- function() { print(x) } print(environment(printMe)) printMe() }) <environment: 0x29785678> [1] 1 2 3 内的printMe的环境:

with

关于您的第二个示例,当您with(E, { environment(printMe) <- environment() printMe() }) [1] 1 2 3 环境attach时,您正在为全局提供E(即E)的对象环境。因此,当您在这种情况下致电x时,它会在全球环境中查找printMe,并且由于附加x,它会找到它。这就是它的工作原理。

我曾经对您有同样的疑虑,所以这个问题可能会对您有所帮助:Environments in R, mapply and get

这也可能有所帮助:Understanding lexical scoping in R