有人可以解释在system.time
评估表达式时会发生什么吗?特别是,为什么在expr
参数中声明的任何变量在全局环境中都可见?
这是system.time
内部的精简版本,除了评估传递给函数的表达式之外什么都不做:
st <- function(expr){
expr
}
st(aa <- 1)
aa
[1] 1
显然,这样做的结果是它在全局环境中创建了变量aa
。这让我感到困惑,因为我认为在函数内部赋值变量使其在范围内是本地的。
这里发生了什么?
答案 0 :(得分:14)
这是因为提供的参数在调用函数的评估框架中进行评估(如R语言定义文档的Section 4.3.3中所述)。
用户在system.time()
中包装的表达式是一个提供的参数,它在位置上与expr
匹配。然后,当expr
的主体强制system.time
的评估时,它将在调用函数的评估框架中进行评估。如果system.time()
调用.GlobalEnv
,那么expr
将会发生任何分配。
修改强>
以下是一个示例,显示expr
在全局环境中进行评估,如果它是提供的(但不是默认)参数。
st2 <- function(expr = newVar <- 33){
expr
}
# Using the default argument -- eval and assignment
# within evaluation frame of the function.
st2()
newVar
Error: object 'newVar' not found
# Using a supplied argument -- eval and assignment
# within the calling function's evaluation frame (here .GlobalEnv)
st2(newVar <- 44)
newVar
# [1] 44
答案 1 :(得分:6)
编辑:根据@ Tommy的评论:评估实际上只在使用参数expr时发生(这是懒惰的评估)。
传递的是语言对象,而不是表达式。您基本上将<-
函数(带有两个参数)嵌套在st()函数调用中,并将<-
调用的结果传递给st。正如您在?assignOps
中看到的那样,<-
函数以静默方式返回指定的值。正如@Josh告诉你的那样,嵌套函数的这种评估发生在调用函数的环境中。
你所做的,相当于
st(mean(1:10))
要了解其中的差异,您可以这样做:
st <- function(expr){
typeof(expr)
}
> st(aa <- 1)
[1] "double"
> st(expression(aa <- 1))
[1] "expression"
对于通话结构,您可以执行以下操作:
st <- function(expr){
str(as.list(match.call()))
}
> st(mean(1:10))
List of 2
$ : symbol st
$ expr: language mean(1:10)
> st(aa <- 1)
List of 2
$ : symbol st
$ expr: language aa <- 1
答案 2 :(得分:1)
我认为 {<1}}在处理该函数之前已经过评估。 POC示例:
expr
所以我认为该函数仅> st <- function(expr){
+ eval(parse(text=expr))
+ }
>
> st('aa <- 1')
> aa
Error: object 'aa' not found
为expr
。另一个例子:
aa
我可能错了,这是一种直觉:)但是,谢谢,这是一个很好的谜题!
<强>更新强>
> st <- function(expr){
+ str(expr)
+ }
>
> st(aa <- 1)
num 1