在这里,我创建了一个未评估的表达式:
e2 <- expression(x+10)
如果我提供的x
被定义为
env <- as.environment(list(x=20))
eval(e2,env)
R将报告错误:
Error in eval(expr, envir, enclos) : could not find function "+"
这是可以理解的,因为env
是从头开始创建的环境,也就是说,它没有定义+
的父环境。
但是,如果我在列表中提供+
以转换为像这样的环境
env <- as.environment(list(x=20,`+`=function(a,b) {a+b}))
eval(e2,env)
评估工作正常并产生30。
但是,当我在列表中定义+
时,它是一个二进制函数,它的主体也使用+ {base}
中定义的。我知道函数返回在R中被懒惰地评估,但为什么这可以工作?如果函数正文中的a+b
被延迟评估,那么当我在eval
内为e2
调用env
时,即使在此环境中定义+
也没有在父环境中,它仍然应该调用+
本身,这应该以无限循环结束。为什么不这样发生?这里的机制是什么?
答案 0 :(得分:4)
在此处定义环境时:
env <- as.environment(list(x=20,`+`=function(a,b) {a+b}))
然后函数定义实际上在.GlobalEnv
中定义(即执行定义的位置。您可以验证这一点:
$ environment(env$`+`)
<environment: R_GlobalEnv>
这个观察值得思考一点:一个函数可以是环境x
的成员,但属于y
(其中“属于”意味着它的对象查找使用{{1}而不是y
)。
x
知道.GlobalEnv
,因为它在父母的某处定义(可通过+
访问)。
顺便提一下,如果您使用search()
代替list2env
,那么您的初始代码就会有效:
as.environment
原因是,与$ env = list2env(list(x = 20))
$ eval(e2, env)
30
不同,as.environment
默认使用当前环境作为新环境的父级(可以通过list2env
参数控制)。相比之下,parent
使用空的环境(从列表创建环境时)。