Как можно увидеть разницу в выходных данных quote () и substitute ()? - PullRequest
0 голосов
/ 18 января 2019

Применительно к одному и тому же R-коду или объектам, кавычка и замена обычно возвращают разные объекты. Как можно сделать это различие очевидным?

is.identical <- function(X){
  out <- identical(quote(X), substitute(X))
  out
}

> tmc <- function(X){
   out <- list(typ = typeof(X), mod = mode(X), cls = class(X))
   out
 }

> df1 <- data.frame(a = 1, b = 2)

Здесь вывод на печать цитаты и замены одинаков.

> quote(df1)
df1
> substitute(df1)
df1

И структура этих двух одинакова.

> str(quote(df1))
 symbol df1
> str(substitute(df1))
 symbol df1

И тип, и режим, и класс одинаковы.

> tmc(quote(df1))
$typ
[1] "symbol"
$mod
[1] "name"
$cls
[1] "name"

> tmc(substitute(df1))
$typ
[1] "symbol"
$mod
[1] "name"
$cls
[1] "name"

И, тем не менее, выходы не одинаковы.

> is.identical(df1)
[1] FALSE

Обратите внимание, что этот вопрос показывает некоторые входы, которые заставляют две функции отображать разные выходы. Однако выходные данные различаются, даже если они выглядят одинаково, и в большинстве обычных тестов они совпадают, как показано в выводе is.identical () выше. Что это за невидимая разница, и как я могу заставить ее появиться?

примечание к тегам: я предполагаю, что общие цитаты LISP и цитата R похожи

1 Ответ

0 голосов
/ 19 января 2019

Причина в том, что поведение 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
...