R 中的词法作用域和环境
lexical scoping and environments in R
我有以下受我原始代码启发的代码片段:
func2 <- function(foos) {
for (foo in foos)
print(eval(parse(text = foo)))
return(foos)
}
func1 <- function(vec) {
text3_obj <- 'text3'
vec <- c(vec, c('text3_obj'))
return(func2(vec))
}
text1_obj <- 'text1'
text2_obj <- 'text2'
func1(c('text1_obj', 'text2_obj'))
在主代码中,我创建了 2 个对象(text1_obj
和 text2_obj
)并将它们的名称传递给 func1()
。此函数在 vector 中添加另一个对象后,调用 func2()
。在 func2()
中,我只是打印对象的值。以下是此代码的输出:
[1] "text1"
[1] "text2"
Error in eval(parse(text = foo)) : object 'text3_obj' not found
进入调试模式后,我意识到甚至 exists('text3_obj')
来自 func2()
内部也会抛出错误。所以我有两个问题:
- 即使
func1()
是 func2()
的直接父级环境;为什么 text3_obj
在 func2()
中不可解析。更高的全局环境变量是可解析的,例如text1_obj
.
- 为什么在调试模式下显式命名环境像 charm 一样有效,例如
exists('text3_obj', where = parent.frame())
和 eval(parse(text = 'text3_obj'), parent.frame())
您将 "calling environment" 与 "enclosing environment." 混淆了,请查看 Hadley 的书中的这些术语 "Advanced R."
http://adv-r.had.co.nz/Environments.html
"calling environment" 是调用函数的环境,由不幸命名的函数 parent.frame
返回。但是,调用环境不用于词法范围。
"enclosing environment" 是创建函数的环境,用于词法范围。您已经在全局环境中创建了 func1
和 func2
。因此,全局环境是两个函数的 "enclosing environment" 并且将用于词法范围 而不管调用环境如何!!
如果你想让func2
使用func1
的执行环境来进行词法作用域,你有(至少)两个选择。您可以在 func1
内创建 func2
func1 <- function(vec) {
func2 <- function(foos) {
for (foo in foos)
print(eval(parse(text = foo)))
return(foos)
}
text3_obj <- 'text3'
vec <- c(vec, c('text3_obj'))
return(func2(vec))
}
然后您的测试按预期工作:
> text1_obj <- 'text1'
> text2_obj <- 'text2'
> func1(c('text1_obj', 'text2_obj'))
[1] "text1"
[1] "text2"
[1] "text3"
[1] "text1_obj" "text2_obj" "text3_obj"
或者,您可以创建 func2
并从 func1
.
中重新分配它的 "enclosing environment"
func2 <- function(foos) {
for (foo in foos)
print(eval(parse(text = foo)))
return(foos)
}
func1 <- function(vec) {
text3_obj <- 'text3'
vec <- c(vec, c('text3_obj'))
environment(func2) <- environment()
return(func2(vec))
}
这也将按预期工作。
我在编写演示代码时发现的一个有趣的花絮...当您从 func1
中重新分配 func2
的环境时,R 似乎创建了 [=20] 的副本=]在func1
的执行环境中。当您返回控制台时,原始 func2
的封闭环境保持不变。证人:
a = function() {
print(identical(environment(a), globalenv()))
}
b = function(x) {
environment(a) <- environment()
a()
}
测试a()
和b()
:
> a()
[1] TRUE
> b()
[1] FALSE
> a()
[1] TRUE
>
这不是我所期望的,但看起来 R 的行为非常出色。如果不是这样,a()
的封闭环境将永久更改为执行环境b()
,并且 FALSE
应该在第二次调用 a()
时返回。
事实证明,您可以使用 <<-
:
在全局环境中强制更改为原始 a()
a = function() {
print(identical(environment(a), globalenv()))
}
b = function(x) {
# set a variable in the execution environment of b() for use later...
montePython = "I'm not dead yet!!"
# change the enclosing environment of a() in the global environment
# rather than making a local copy of a() in b()'s execution environment.
environment(a) <<- environment()
a()
}
测试a()
和b()
:
> a()
[1] TRUE
> b()
[1] FALSE
> a()
[1] FALSE
>
有趣的是,这意味着 b()
的(通常是临时的)执行环境即使在 b()
终止后仍然存在于内存中,因为 a()
仍然引用环境,所以它不能'不会被垃圾收集。证人:
> environment(a)$montePython
[1] "I'm not dead yet!!"
我有以下受我原始代码启发的代码片段:
func2 <- function(foos) {
for (foo in foos)
print(eval(parse(text = foo)))
return(foos)
}
func1 <- function(vec) {
text3_obj <- 'text3'
vec <- c(vec, c('text3_obj'))
return(func2(vec))
}
text1_obj <- 'text1'
text2_obj <- 'text2'
func1(c('text1_obj', 'text2_obj'))
在主代码中,我创建了 2 个对象(text1_obj
和 text2_obj
)并将它们的名称传递给 func1()
。此函数在 vector 中添加另一个对象后,调用 func2()
。在 func2()
中,我只是打印对象的值。以下是此代码的输出:
[1] "text1"
[1] "text2"
Error in eval(parse(text = foo)) : object 'text3_obj' not found
进入调试模式后,我意识到甚至 exists('text3_obj')
来自 func2()
内部也会抛出错误。所以我有两个问题:
- 即使
func1()
是func2()
的直接父级环境;为什么text3_obj
在func2()
中不可解析。更高的全局环境变量是可解析的,例如text1_obj
. - 为什么在调试模式下显式命名环境像 charm 一样有效,例如
exists('text3_obj', where = parent.frame())
和eval(parse(text = 'text3_obj'), parent.frame())
您将 "calling environment" 与 "enclosing environment." 混淆了,请查看 Hadley 的书中的这些术语 "Advanced R."
http://adv-r.had.co.nz/Environments.html
"calling environment" 是调用函数的环境,由不幸命名的函数 parent.frame
返回。但是,调用环境不用于词法范围。
"enclosing environment" 是创建函数的环境,用于词法范围。您已经在全局环境中创建了 func1
和 func2
。因此,全局环境是两个函数的 "enclosing environment" 并且将用于词法范围 而不管调用环境如何!!
如果你想让func2
使用func1
的执行环境来进行词法作用域,你有(至少)两个选择。您可以在 func1
func2
func1 <- function(vec) {
func2 <- function(foos) {
for (foo in foos)
print(eval(parse(text = foo)))
return(foos)
}
text3_obj <- 'text3'
vec <- c(vec, c('text3_obj'))
return(func2(vec))
}
然后您的测试按预期工作:
> text1_obj <- 'text1'
> text2_obj <- 'text2'
> func1(c('text1_obj', 'text2_obj'))
[1] "text1"
[1] "text2"
[1] "text3"
[1] "text1_obj" "text2_obj" "text3_obj"
或者,您可以创建 func2
并从 func1
.
func2 <- function(foos) {
for (foo in foos)
print(eval(parse(text = foo)))
return(foos)
}
func1 <- function(vec) {
text3_obj <- 'text3'
vec <- c(vec, c('text3_obj'))
environment(func2) <- environment()
return(func2(vec))
}
这也将按预期工作。
我在编写演示代码时发现的一个有趣的花絮...当您从 func1
中重新分配 func2
的环境时,R 似乎创建了 [=20] 的副本=]在func1
的执行环境中。当您返回控制台时,原始 func2
的封闭环境保持不变。证人:
a = function() {
print(identical(environment(a), globalenv()))
}
b = function(x) {
environment(a) <- environment()
a()
}
测试a()
和b()
:
> a()
[1] TRUE
> b()
[1] FALSE
> a()
[1] TRUE
>
这不是我所期望的,但看起来 R 的行为非常出色。如果不是这样,a()
的封闭环境将永久更改为执行环境b()
,并且 FALSE
应该在第二次调用 a()
时返回。
事实证明,您可以使用 <<-
:
a()
a = function() {
print(identical(environment(a), globalenv()))
}
b = function(x) {
# set a variable in the execution environment of b() for use later...
montePython = "I'm not dead yet!!"
# change the enclosing environment of a() in the global environment
# rather than making a local copy of a() in b()'s execution environment.
environment(a) <<- environment()
a()
}
测试a()
和b()
:
> a()
[1] TRUE
> b()
[1] FALSE
> a()
[1] FALSE
>
有趣的是,这意味着 b()
的(通常是临时的)执行环境即使在 b()
终止后仍然存在于内存中,因为 a()
仍然引用环境,所以它不能'不会被垃圾收集。证人:
> environment(a)$montePython
[1] "I'm not dead yet!!"