Причина в том, что поведение substitute()
отличается в зависимости от того, где вы его называете, или, точнее, от того, на что вы его называете.
Понимание того, что произойдет, требует очень тщательного анализа(тонкая) документация для substitute()
, в частности:
Подстановка происходит путем изучения каждого компонента дерева разбора следующим образом: Если это не связанный символ в env, он не изменяется.Если это объект обещания, то есть формальный аргумент функции или явно созданный с использованием delayedAssign (), слот выражения обещания заменяет символ.Если это обычная переменная, ее значение подставляется, если только env не является .GlobalEnv, в этом случае символ остается без изменений.
Таким образом, по сути, есть три варианта.
В этомcase:
> df1 <- data.frame(a = 1, b = 2)
> identical(quote(df1),substitute(df1))
[1] TRUE
df1
- это «обычная переменная», , но она вызывается в .GlobalEnv
, поскольку аргумент env
по умолчанию соответствует текущей среде оценки.Следовательно, мы находимся в самом последнем случае, когда символ, df1
, остается неизменным, и поэтому он идентичен результату quote(df1)
.
В контексте функции:
is.identical <- function(X){
out <- identical(quote(X), substitute(X))
out
}
Важным отличием является то, что теперь мы вызываем эти функции на X
, а не df1
.Для большинства пользователей R это глупое, тривиальное различие, но при игре с тонкими инструментами, такими как substitute
, это становится важным.X
является формальным аргументом функции, поэтому подразумевается, что мы находимся в другом случае документированного поведения.
В частности, он говорит, что теперь "слот выраженияобещание заменяет символ ".Мы можем увидеть, что это значит, если мы debug()
функцию и исследуем объекты в контексте функциональной среды:
> debugonce(is.identical)
> is.identical(X = df1)
debugging in: is.identical(X = df1)
debug at #1: {
out <- identical(quote(X), substitute(X))
out
}
Browse[2]>
debug at #2: out <- identical(quote(X), substitute(X))
Browse[2]> str(quote(X))
symbol X
Browse[2]> str(substitute(X))
symbol df1
Browse[2]> Q
Теперь мы можем видеть, что произошло именно то, что сказано в документации (Ха! Так очевидно!;))
X
- это формальный аргумент или обещание, которое согласно R равно , а не то же самое, что df1
.Для большинства людей, пишущих функции, они фактически одинаковы, но внутренняя реализация не согласна.X
является объектом обещания, а substitute
заменяет символ X
на тот, на который он «указывает», а именно df1
.Это то, что документы имеют в виду под «слотом выражения обещания»;это то, что R видит, когда в X = df1
части вызова функции.
Чтобы округлить все, попробуйте угадать, что произойдет в этом случае:
is.identical <- function(X){
out <- identical(quote(A), substitute(A))
out
}
is.identical(X = df1)
(Подсказка: сейчасA
не является «связанным символом в среде».)
Последний пример, более наглядно иллюстрирующий последний случай в документах, с запутанным исключением:
#Ordinary variable, but in .GlobalEnv
> a <- 2
> substitute(a)
a
#Ordinary variable, but NOT in .GlobalEnv
> e <- new.env()
> e$a <- 2
> substitute(a,env = e)
[1] 2