Какая разница между заместителем и цитатой в R

В официальных документах говорится:

substitute возвращает дерево разбора для (unevaluated) выражения expr, заменяя любые переменные, связанные в env.

quote просто возвращает свой аргумент. Аргумент не оценивается и может быть любым выражением R.

Но когда я пытаюсь:

> x <- 1
> substitute(x)
x
> quote(x)
x

Похоже, и quote и substitute возвращает выражение, переданное в качестве аргумента для них.

Итак, мой вопрос в том, какая разница между substitute и quote, и что это значит "заменять любые переменные, связанные в env"?

Ответ 1

Вот пример, который может помочь вам легко увидеть разницу между quote() и substitute() в одном из параметров (аргументы функции обработки), где чаще всего используется substitute():

f <- function(argX) {
   list(quote(argX), substitute(argX), argX)
}

suppliedArgX <- 100
f(argX = suppliedArgX)
# [[1]]
# argX
# 
# [[2]]
# suppliedArgX
# 
# [[3]]
# [1] 100

Ответ 2

Возможно, этот раздел документации поможет несколько:

Замена происходит путем изучения каждого компонента дерева разбора следующим образом: если он не является связанным символом в env, он не изменяется. Если это объект обещания, т.е. Формальный аргумент функции или явно созданный с использованием delayedAssign(), слот выражения обещания заменяет символ. Если это обычная переменная, ее значение заменяется, если только env не является.GlobalEnv, и в этом случае символ остается неизменным.

Обратите внимание на окончательный бит и рассмотрим этот пример:

e <- new.env()
assign(x = "a",value = 1,envir = e)
> substitute(a,env = e)
[1] 1

Сравните это с:

> quote(a)
a

Таким образом, есть две основные ситуации, когда подстановка будет происходить: когда мы используем ее для аргумента функции, а когда env - это некоторая среда, .GlobalEnv от .GlobalEnv. Вот почему ваш конкретный пример сбивает с толку.

Для другого сравнения с quote рассмотрим изменение функции myplot в разделе примеров:

myplot <- function(x, y)
    plot(x, y, xlab = deparse(quote(x)),
             ylab = deparse(quote(y)))

и вы увидите, что quote действительно не делает никакой замены.

Ответ 3

Что касается вашего вопроса, почему GlobalEnv рассматривается как исключение для замены, это всего лишь наследие определения языка S. From The R (https://cran.r-project.org/doc/manuals/r-release/R-lang.html # Замены):

Особое исключение для замены на верхнем уровне является, по общему признанию, своеобразным. Он был унаследован от S, и обоснование, скорее всего, не позволяет контролировать, какие переменные могут быть привязаны на этом уровне, так что было бы лучше просто сделать замену действием как цитатой.

Ответ 4

R имеет ленивую оценку, поэтому идентификация токена имени переменной немного менее понятна, чем на других языках. Это используется в таких библиотеках, как dplyr где вы можете писать, например:

summarise(mtcars, total_cyl = sum(cyl))

Мы можем спросить, что означает каждый из этих токенов: summarise и sum определенные функции, mtcars - это определенный кадр данных, total_cyl - это аргумент ключевого слова для summarise функции. Но что такое cyl?

> cyl
Error: object 'cyl' not found

Это не что-то! Ну, еще нет. R не оценивает его сразу, но рассматривает его как выражение, которое будет разбираться позже с некоторым деревом разбора, которое отличается от глобальной среды, в которой работает ваша командная строка, в частности, где определены столбцы mtcars. Где-то в кишках dplyr происходит нечто подобное:

> substitute(cyl, mtcars)
[1] 6 6 4 6 8 ...

Внезапно cyl что-то значит. Для этой substitute.

Итак, для чего quote? Иногда вы хотите, чтобы ваше лениво оцениваемое выражение представлялось где-то еще до его оценки, т.е. Вы хотите отобразить фактический код, который вы пишете, без каких-либо (или только некоторых) значений, замененных. Документы, которые вы цитировали, объясняют это обычным для "информационных ярлыков для наборов данных и графиков".

Так, например, вы можете создать кавычное выражение, а затем оба напечатать неоценимое выражение в диаграмме, чтобы показать, как вы рассчитали и фактически вычислили с помощью выражения.

expr <- quote(x + y)
print(expr) # x + y
eval(expr, list(x = 1, y = 2)) # 3

Обратите внимание, что substitute может также использовать этот трюк выражения, предоставляя вам возможность анализировать только его часть. Таким образом, его функции являются надмножеством quote.

expr <- substitute(x + y, list(x = 1))
print(expr) # 1 + y
eval(expr, list(y = 2)) # 3