为什么在system.time()中计算表达式会使变量在全局环境中可用?

时间:2011-11-01 20:44:41

标签: r scope

有人可以解释在system.time评估表达式时会发生什么吗?特别是,为什么在expr参数中声明的任何变量在全局环境中都可见?

这是system.time内部的精简版本,除了评估传递给函数的表达式之外什么都不做:

st <- function(expr){
  expr
}

st(aa <- 1)
aa
[1] 1

显然,这样做的结果是它在全局环境中创建了变量aa。这让我感到困惑,因为我认为在函数内部赋值变量使其在范围内是本地的。

这里发生了什么?

3 个答案:

答案 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