Почему локальный ({...}) должен быть определен с использованием двух раундов цитирования выражения?
Я пытаюсь понять, как R local
функция работает. С его помощью вы можете открыть временную локальную область, что означает, что происходит в local
(в частности, определения переменных), остается в local
, Только последнее значение блока возвращается во внешний мир. Так:
x <- local({
a <- 2
a * 2
})
x
## [1] 4
a
## Error: object 'a' not found
local
определяется так:
local <- function(expr, envir = new.env()){
eval.parent(substitute(eval(quote(expr), envir)))
}
Насколько я понимаю, происходит два раунда цитирования выражения и последующей оценки:
eval(quote([whatever expr input]), [whatever envir input])
генерируется как неоцененный вызовsubstitute
,- Звонок оценивается в
local
Кадр вызывающего абонента (который в нашем случае - Глобальная среда), так[whatever expr input]
оценивается в[whatever envir input]
Тем не менее, я не понимаю, почему шаг 2 является обязательным. Почему я не могу просто определить local
как это:
local2 <- function(expr, envir = new.env()){
eval(quote(expr), envir)
}
Я думаю, что это оценивает выражение expr
в пустой среде? Таким образом, любая переменная, определенная в expr
должен существовать в envir
и поэтому исчезают после окончания local2
?
Однако, если я попробую это, я получу:
x <- local2({
a <- 2
a * 2
})
x
## [1] 4
a
## [1] 2
Так a
утечки в глобальную окружающую среду. Почему это?
РЕДАКТИРОВАТЬ: Еще более загадочным: Почему это не происходит для:
eval(quote({a <- 2; a*2}), new.env())
## [1] 4
a
## Error: object 'a' not found
1 ответ
Параметры в функции R передаются как обещания. Они не оцениваются, если не указано значение. Так посмотри на
# clean up first
if exists("a") rm(a)
f <- function(x) print(1)
f(a<-1)
# [1] 1
a
# Error: object 'a' not found
g <- function(x) print(x)
g(a<-1)
# [1] 1
a
# [1] 1
Обратите внимание, что в g()
функция, мы используем значение, переданное функции, которая является этим назначением a
так что создает a
в глобальной среде. С f()
, эта переменная никогда не создается, потому что этот параметр функции остается обещанием, а конец никогда не оценивался.
Если вы хотите получить доступ к параметру без его оценки, вам нужно использовать что-то вроде match.call()
или же subsititute()
, local()
Функция делает последнее.
Если вы удалите eval.parent()
вы увидите, что подстановка помещает необработанное выражение из параметра в новый вызов eval()
,
h <- function(expr, envir = new.env()){
substitute(eval(quote(expr), envir))
}
h(a<-1)
# eval(quote(a <- 1), new.env())
Где, как будто вы делаете
j<- function(x) {
quote(x)
}
j(a<-1)
# x
вы на самом деле не создаете новый вызов функции. Дальше больше, когда ты eval()
это выражение, вы запускаете оценку x
из исходной среды вызова (запускающей оценку обещания), а не оценки выражения в новой среде.
local()
затем использует eval.parent()
так что вы можете использовать существующие переменные в среде вашего блока. Например
b<-5
local({
a <- b
a * 2
})
# [1] 10
Посмотрите на поведение здесь
local2 <- function(expr, envir = new.env()){
eval(quote(expr), envir)
}
local2({a<-5; a})
# [1] 5
local2({a<-5; a}, list(a=100, expr="hello"))
# [1] "hello"
Посмотрите, как, когда мы используем непустую среду, eval()
смотрит вверх expr
в среде это не оценка вашего блока кода в среде.