Класс expr и exprs различаются по rlang в R! Почему?

Я не уверен, что здесь об этом спрашивали, но я здесь очень запутался. Я читаю эту замечательную книгу под названием Advanced R от Хэдли Уикхема, которую здесь.

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

library(rlang)
cement1 <- function(x) {
  dots <- expr(x)
  print(class(dots))
  #paste(expr_name(x))
}

cement2 <- function(y,z) {
  dots <- exprs(y,z)
  print(class(dots))
  #paste(purrr::map(dots, expr_name), collapse = " ")
}

Выполнение вышеуказанного cement1 без каких-либо параметров возвращает мне класс точек как «имя».

Однако, когда я запускаю функцию cement2 с дополнительным параметром, класс возвращает «список», {простое добавление class (expr (x)) возвращает «name», тогда как class (exprs (x)) возвращает «list»}.

Я не понимаю, почему он печатает другой класс, возвращаемый expr и exprs. Единственное различие, которое, как мне казалось, я знал о них, заключалось в том, что один имеет дело с одним параметром, другой - с несколькими параметрами, но я могу ошибаться, я мог пропустить некоторые детали.

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

cement1(Hello) #Returns , Error in type_of(.x) : object 'Hello' not found 
cement2(Hello) #Works very well and returns, [1] "y z"

Итак, я попытался найти причину, по которой cement1 не удалось, а затем распечатал их классы, и именно тогда я понял, что expr и exprs возвращают разные классы.

Мой вопрос:

1) Они задуманы, если да, то почему? Или я совершаю ужасную ошибку, которую сейчас не вижу.

2) Разве cement1 не может работать, если нет, то как правильно?

Прошу прощения за слишком длинные предложения. Мой родной язык не английский, поэтому, если есть что-то глупое, пожалуйста, дайте мне знать, я исправлю это. Надеюсь, это не дубликат, я пытался найти ответ, но сам не нашел.

Спасибо за любую помощь.

Версия R: 3.4.2 rlang: 0.2.0


person PKumar    schedule 25.05.2018    source источник


Ответы (1)


1) Да, возвращаемые значения expr и exprs различаются по конструкции. На странице справки ?expr:

enexpr () и expr () захватывают одно необработанное выражение.

enexprs () и exprs () захватывают список необработанных выражений, включая выражения, содержащиеся в ....

2) expr_name() ожидает выражение в кавычках, например то, что создается expr(). Итак, вам нужно изменить свой cement1, чтобы вызывать expr_name() на dots, а не на x. Вы также можете удалить paste, потому что вы ничего не объединяете.

cement1 <- function(x) {
  dots <- expr(x)
  # print(class(dots))      ## Commented out for clarity
  expr_name(dots)           ## The input to expr_name is now effectively expr(x)
}
cement1( Hello )
# "x"

Ваша функция cement2 в основном вызывает expr_name() для каждого элемента списка, возвращаемого exprs(), а затем объединяет результаты в одну строку.

2a) Теперь, когда ваша cement1 работает, мы можем ее улучшить. В настоящее время функция не использует входной аргумент x. expr() просто захватывает неоцененное выражение, и это выражение всегда будет x, независимо от того, как вы назовете свой аргумент:

cement1.1 <- function( completelyIgnoredName ) {
  dots <- expr(x)
  expr_name(dots)
}
cement1.1( Hello )
# "x"

Однако, если вы замените expr() на enexpr(), функция заменит выражение, указанное в качестве аргумента функции, и вместо этого захватит это:

cement1.2 <- function(x) {
  dots <- enexpr(x)
  expr_name(dots)
}
cement1.2( Hello )
# "Hello"
person Artem Sokolov    schedule 23.08.2018