Почему вычисление выражения в system.time () делает переменные доступными в глобальной среде? - PullRequest
12 голосов
/ 02 ноября 2011

Может кто-нибудь объяснить, что происходит, когда выражение оценивается в system.time?В частности, почему любые переменные, которые объявлены в аргументе expr, видны в глобальной среде?

Вот сокращенная версия внутренностей system.time, которая не делает ничего, кроме вычисления выраженияэто передается функции:

st <- function(expr){
  expr
}

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

Очевидно, что это создает переменную aa в глобальной среде.Это сбивает меня с толку, так как я думал, что присвоение переменной внутри функции делает ее локальной в области видимости.

Что здесь происходит?

Ответы [ 3 ]

14 голосов
/ 02 ноября 2011

Это потому, что предоставленные аргументы оцениваются в кадре оценки вызывающей функции (как описано в Раздел 4.3.3 документа определения языка R).

Выражение, заключенное пользователем в system.time(), является предоставленным аргументом, который позиционно сопоставляется с expr.Затем, когда оценка expr принудительно вводится в теле system.time, она оценивается в кадре оценки вызывающей функции.Если system.time() был вызван из .GlobalEnv, то здесь будут выполняться любые назначения, являющиеся частью expr.

РЕДАКТИРОВАТЬ:

Вотпример, показывающий, что expr оценивается в глобальной среде, если это предоставленный (но не default ) аргумент.

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
6 голосов
/ 02 ноября 2011

РЕДАКТИРОВАТЬ: согласно @ комментарию Томми: оценка на самом деле происходит только после использования аргумента 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
1 голос
/ 02 ноября 2011

I думаю expr оценивается до обработки этого значения для функции. Пример POC:

> 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

Я могу ошибаться, это скорее интуиция :) Но спасибо, это хорошая головоломка!


Обновление:

> 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
...