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

Являются ли эти строки или переменные?

Исходя из фона C/Python/Java, мне трудно понять некоторый синтаксис R, где литералы выглядят как переменные, но, похоже, ведут себя как строки. Например:

library(ggplot2)
library("ggplot2")

Две линии ведут себя эквивалентно. Однако я ожидаю, что первая строка будет означать "загрузить библиотеку, имя которой хранится в переменной ggplot2" и дать ошибку, например object 'ggplot2' not found.

Говоря о ggplot2:

ggplot(data, aes(factor(arrivalRate), responseTime, fill=factor(mode))) +
  geom_violin(trim=FALSE, position=dodge)

Переменные arrivalRate, responseTime и mode не существуют, но каким-то образом R знает, как их искать внутри фрейма данных data. Я предполагаю, что aes фактически получает строки, которые затем обрабатываются с помощью чего-то вроде eval.

Как код R parse заканчивается тем, что интерпретирует некоторые литералы как строки?

4b9b3361

Ответ 1

promises

Когда аргумент передается функции, он не передается как значение, а передается как обещание, состоящее из

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

Пакет pryr может отображать информацию в обещании:

library(pryr)

g <- function(x) promise_info(x)
g(ggplot2)

даяние:

$code
ggplot2  <-- the promise x represents the expression ggplot2

$env
<environment: R_GlobalEnv>  <-- if evaluated it will be done in this environment

$evaled
[1] FALSE  <-- it has not been evaluated

$value
NULL  <-- not filled in because promise has not been evaluated

Единственный из вышеперечисленных слотов в выводе pryr, к которому можно получить доступ на уровне R без записи функции C для его выполнения (или с использованием пакета, такого как pryr, который обращается к такому C-коду), является слотом кода. Это можно сделать с помощью функции R substitute(x) (или других средств). В терминах вывода pryr substitute, примененного к обещанию, возвращает слот кода без оценки обещания. То есть, слот значения не изменяется. Если бы мы обратились к x обычным способом, то есть не через substitute, тогда код был бы оценен в среде обещаний, сохраненном в слоте значения, а затем передан в выражение в функции, которая обращается к нему.

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

f <- function(x) as.character(substitute(x))
f("ggplot2")
## [1] "ggplot2"
f(ggplot2)
## [1] "ggplot2"

Библиотека

Фактически, library использует эту идиому, т.е. as.character(substitute(x)), для обработки своего первого аргумента.

АЕС

Функция aes использует match.call, чтобы получить весь вызов как выражение, и поэтому в некотором смысле является альтернативой substitute. Например:

h <- function(x) match.call()
h(pi + 3)
## h(x = pi + 3)

Примечание

Нельзя сказать, не глядя на документацию или код функции, как она будет обрабатывать ее аргументы.

Ответ 2

Интересным причудом языка R является способ оценки выражений. В большинстве случаев R ведет себя так, как вы ожидали. Выражения в кавычках рассматриваются как строки, все остальное рассматривается как переменная, функция или другой токен. Но некоторые функции допускают "нестандартную оценку", в которой некорректное выражение оценивается более или менее, как если бы оно было цитируемой переменной. Наиболее распространенным примером этого является способ загрузки библиотек R (который допускает имена некотируемых или цитируемых библиотек) и его сжатый интерфейс формул. Другие пакеты могут использовать NSE. Hadley Wickham широко использует его во всех своих чрезвычайно популярных пакетах tidyverse. Помимо сохранения пользователем нескольких символов ввода, NSE имеет ряд полезных свойств для динамического программирования.

Как отмечалось в другом ответе, Wickham имеет отличный учебник о том, как все это работает. В пользовательском интерфейсе пользователя lionel также есть отличный рабочий документ по этой теме.

Ответ 3

Концепция называется "нестандартная оценка", и существует множество различных способов ее использования в разных R-функциях. См. эту книгу для введения.

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

Ответ 4

Линии

library(ggplot2)
library("ggplot2")

не эквивалентны. В первой строке ggplot2 - символ, который может или не могут быть связаны с какой-либо ценностью. Во второй строке "ggplot2" есть символьный вектор длины один.

Функция, однако, может манипулировать аргументами, которые она получает без оценивая их и может решить рассматривать оба случая равнозначно, что, по-видимому, есть library.

Вот пример того, как манипулировать неоценимым выражением:

> f <- function(x) match.call()  # return unevaluated function call
> x <- f(foo)
> x
f(x = foo)
> mode(x)
[1] "call"
> x[[1]]
f
> x[[2]]
foo
> mode(x[[2]])
[1] "name"
> as.character(x[[2]])
[1] "foo"
> x <- f("foo")
> mode(x[[2]])
[1] "character"