Подтвердить что ты не робот

Почему оценка выражения в system.time() делает переменные доступными в глобальной среде?

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

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

st <- function(expr){
  expr
}

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

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

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

4b9b3361

Ответ 1

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

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

EDIT:

Здесь пример, показывающий, что 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 evaluation frame (here .GlobalEnv)
st2(newVar <- 44)
newVar
# [1] 44

Ответ 2

EDIT: в соответствии с комментарием @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

Ответ 3

Я думаю, что 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

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


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