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

时间:2021-06-06 23:35:02

Can somebody please explain what happens when an expression is evaluated in system.time? In particular, why are any variables that are declared in the expr argument visible in the global environment?

有人能解释一下当一个表达式在system.time中被求值时会发生什么吗?特别是,为什么在expr参数中声明的变量在全局环境中是可见的?

Here is a pared-down version of the innards of system.time that does nothing other than evaluating the expression that is passed to the function:

这是系统内部的简化版本。除了计算传递给函数的表达式之外什么都不做的时间:

st <- function(expr){
  expr
}

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

Clearly the effect of this is that it creates the variable aa in the global environment. This baffles me, since I thought that assigning a variable inside a function makes it local in scope.

显然,它的效果是在全局环境中创建变量aa。这让我很困惑,因为我认为在函数中赋值一个变量会使它在作用域内具有局部性。

What happens here?

这里发生了什么?

3 个解决方案

#1


14  

It is because supplied arguments are evaluated in the evaluation frame of the calling function (as described in Section 4.3.3 of the R Language Definition document).

这是因为提供的参数在调用函数的评估框架中进行评估(如R语言定义文档4.3.3节所述)。

The expression wrapped by the user in system.time() is a supplied argument which gets matched positionally to expr. Then, when expr's evaluation is forced in the body of system.time, it is evaluated in the evaluation frame of the calling function. If system.time() was called from the .GlobalEnv, that is where any assignments that are a part of expr will take place.

user在system.time()中包装的表达式是一个提供的参数,该参数在位置上与expr匹配。然后,在系统主体中强制执行expr的评价。时间,在调用函数的求值框架中求值。如果system.time()是从. globalenv调用的,则所有属于expr的赋值都将在这里执行。

EDIT:

编辑:

Here's an example showing that expr is evaluated in the global environment if it is a supplied (but not a default) argument.

这里有一个例子,说明了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

#2


6  

EDIT : as per @Tommy's comment: The evaluation actually only takes place once the argument expr is used (that's the lazy evaluation).

编辑:正如@Tommy的评论:评估实际上只在使用参数expr时才进行(这是惰性评估)。

What is passed is a language object, not an expression. You basically nest the <- function (with two arguments) within the st() function call, and the result of the <- call is passed to to st. As you can see in ?assignOps, the <- function returns the assigned value silently. As @Josh told you already, this evaluation of the nested function takes place in the environment the function is called from.

传递的是语言对象,而不是表达式。基本上,您将<- function(带有两个参数)嵌套在st()函数调用中,并且<-调用的结果被传递给st,您可以在?assignOps中看到,<-函数无声地返回分配的值。正如@Josh已经告诉您的,对嵌套函数的评估发生在调用该函数的环境中。

What you do, is equivalent to

你所做的,等于

st(mean(1:10))

To see the difference, you can do:

要看到区别,你可以这样做:

st <- function(expr){
  typeof(expr)
}
> st(aa <- 1)
[1] "double"
> st(expression(aa <- 1))
[1] "expression"

For the structure of the call, you can do:

至于电话的结构,你可以:

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

#3


1  

I think the expr is evaluated before handling that to the function. POC example:

我认为在对函数进行处理之前对expr进行了评估。POC的例子:

> st <- function(expr){
+   eval(parse(text=expr))
+ }
> 
> st('aa <- 1')
> aa
Error: object 'aa' not found

So I think the function gets expr as only aa. Another example:

我认为这个函数只有aa。另一个例子:

> st <- function(expr){
+   str(expr)
+ }
> 
> st(aa <- 1)
 num 1

I might be wrong, it is rather an intuition :) But thanks, that is a good puzzle!

我可能错了,这是一种直觉:)但是谢谢,这是一个很好的谜!


Update:

更新:

> system.time(a <- 1)
   user  system elapsed 
      0       0       0 
> a
[1] 1
> rm(a)
> fn <- function() a <- 1
> system.time(fn())
   user  system elapsed 
      0       0       0 
> a
Error: object 'a' not found

#1


14  

It is because supplied arguments are evaluated in the evaluation frame of the calling function (as described in Section 4.3.3 of the R Language Definition document).

这是因为提供的参数在调用函数的评估框架中进行评估(如R语言定义文档4.3.3节所述)。

The expression wrapped by the user in system.time() is a supplied argument which gets matched positionally to expr. Then, when expr's evaluation is forced in the body of system.time, it is evaluated in the evaluation frame of the calling function. If system.time() was called from the .GlobalEnv, that is where any assignments that are a part of expr will take place.

user在system.time()中包装的表达式是一个提供的参数,该参数在位置上与expr匹配。然后,在系统主体中强制执行expr的评价。时间,在调用函数的求值框架中求值。如果system.time()是从. globalenv调用的,则所有属于expr的赋值都将在这里执行。

EDIT:

编辑:

Here's an example showing that expr is evaluated in the global environment if it is a supplied (but not a default) argument.

这里有一个例子,说明了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

#2


6  

EDIT : as per @Tommy's comment: The evaluation actually only takes place once the argument expr is used (that's the lazy evaluation).

编辑:正如@Tommy的评论:评估实际上只在使用参数expr时才进行(这是惰性评估)。

What is passed is a language object, not an expression. You basically nest the <- function (with two arguments) within the st() function call, and the result of the <- call is passed to to st. As you can see in ?assignOps, the <- function returns the assigned value silently. As @Josh told you already, this evaluation of the nested function takes place in the environment the function is called from.

传递的是语言对象,而不是表达式。基本上,您将<- function(带有两个参数)嵌套在st()函数调用中,并且<-调用的结果被传递给st,您可以在?assignOps中看到,<-函数无声地返回分配的值。正如@Josh已经告诉您的,对嵌套函数的评估发生在调用该函数的环境中。

What you do, is equivalent to

你所做的,等于

st(mean(1:10))

To see the difference, you can do:

要看到区别,你可以这样做:

st <- function(expr){
  typeof(expr)
}
> st(aa <- 1)
[1] "double"
> st(expression(aa <- 1))
[1] "expression"

For the structure of the call, you can do:

至于电话的结构,你可以:

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

#3


1  

I think the expr is evaluated before handling that to the function. POC example:

我认为在对函数进行处理之前对expr进行了评估。POC的例子:

> st <- function(expr){
+   eval(parse(text=expr))
+ }
> 
> st('aa <- 1')
> aa
Error: object 'aa' not found

So I think the function gets expr as only aa. Another example:

我认为这个函数只有aa。另一个例子:

> st <- function(expr){
+   str(expr)
+ }
> 
> st(aa <- 1)
 num 1

I might be wrong, it is rather an intuition :) But thanks, that is a good puzzle!

我可能错了,这是一种直觉:)但是谢谢,这是一个很好的谜!


Update:

更新:

> system.time(a <- 1)
   user  system elapsed 
      0       0       0 
> a
[1] 1
> rm(a)
> fn <- function() a <- 1
> system.time(fn())
   user  system elapsed 
      0       0       0 
> a
Error: object 'a' not found