在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
中的嵌套函数不能访问自由变量?
答案 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
然后x
和printMe
都在全局环境中定义,因此它可以正常工作。您还可以更改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
内定义with
,printMe
的环境将是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