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