Многоточие `...` для списка невычисленных выражений

Как я могу написать функцию в Base R для захвата точки-точки-точки (многоточия) и возврата списка неоцененных выражений?

В этом примере пользователь вводит выражения в фигурные скобки и получает нужные мне выходные данные:

fun1 <- function(...) {
    as.list(substitute(list(...)))[-1L]
}
fun1({a = 2}, {a2 = a * 2})
> [[1]]
> {
>     a = 2
> }
> 
> [[2]]
> {
>     a2 = a * 2
> }

Я бы хотел, чтобы пользователь выполнил тот же вызов, что и выше, без фигурных скобок и получил тот же вывод, что и в fun1():

fun2 <- function(...) {
    # CODE HERE
}
fun2(a = 2, a2 = a * 2)

Это похоже на проблему XY. Для чего именно вам это нужно? Требуете ли вы, чтобы функция принимала аргументы вида name = expr, или вы хотите принимать произвольное выражение и что вы хотите делать с результатом?

Konrad Rudolph 13.07.2024 14:23

Добавляю к моему предыдущему комментарию: в зависимости от вашего варианта использования существуют разные подходы к решению этой проблемы. Один конкретный занимает «коробка», которая ожидает аргументы формы name = expr.

Konrad Rudolph 13.07.2024 14:24

Да, я согласен. Я пытаюсь удовлетворить очень специфические требования для подтверждения концепции, но постараюсь убедить директора, что есть способы получше. Спасибо за ссылку, посмотрю.

Vincent 13.07.2024 14:26

Не поймите меня неправильно: я не говорю, что то, что вы делаете, — плохая идея или вообще неосуществимая (хотя пользователь 2554330 правильно объяснил здесь синтаксическое ограничение R!). На самом деле, еще один способ обойти дилемму — использовать присваивание <- вместо = (хотя лично я бы этого не делал, так как налагаю строгий запрет на <- в своих проектах).

Konrad Rudolph 13.07.2024 14:28
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
84
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Сделать это непросто, потому что = в первом примере — это оператор присваивания, а = во втором примере просто привязывает выражения к именам — это разные вещи.

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

fun3 <- function(...) { 
  args <- as.list(substitute(list(...)))[-1L]
  names <- names(args)
  result <- args
  names(result) <- NULL
  for (i in seq_along(args))
    if (nzchar(names[i]))
      result[[i]] <- call(" = ", as.name(names[i]), args[[i]])
  result
}

fun3(a = 2, a2 = a * 2, 123)
#> [[1]]
#> a = 2
#> 
#> [[2]]
#> a2 = a * 2
#> 
#> [[3]]
#> [1] 123

Created on 2024-07-13 with reprex v2.1.0

Спасибо за решение. Ваше предупреждение очень разумно.

Vincent 13.07.2024 14:27

Мне нравится предупреждение и ваш подход к этому, но неявное приведение вывода nchar() к логическому значению для меня читается как Python. Я бы предпочел использовать здесь if (nzchar(names[i])).

SamR 13.07.2024 15:33

@SamR: это хорошее предложение, я изменил его. Кстати, я думаю, что C оказал большее влияние на мое мышление, чем Python!

user2554330 13.07.2024 19:07

Обновление: добавление некоторых решений к исходным ответам, чтобы соответствовать ожидаемому результату.

Это немного хакерское решение, основанное на rlang


fun2 <- \(...){
  random_things_from_users <- as.list(substitute(rlang::enquos(...)))

  random_things_from_users <- random_things_from_users[-1L]

  print(random_things_from_users)
}

fun2(a = 2, a2 = a * 2)
#> $a
#> [1] 2
#> 
#> $a2
#> a * 2
fun3 = \(...){
  
  user_args = as.list(substitute(rlang::enquos(...)))[-1L]
  
  user_names <- names(user_args)
  
  args_from_users <- purrr::map2(user_args,
                                 user_names,
                                 \(args, user_names) as.name(glue::glue('{user_names} = {deparse(args)}')))
  
  names(args_from_users) <- NULL
  
  
  
  args_from_users
}


fun3(a = 2, a2 = a * 2, b = 'hello world')
#> [[1]]
#> `a = 2`
#> 
#> [[2]]
#> `a2 = a * 2`
#> 
#> [[3]]
#> `b = "hello world"`


fun4 = \(...){
  
  user_args = as.list(substitute(rlang::enquos(...)))[-1L]
  
  user_names <- names(user_args)
  
  args_from_users <- mapply(\(args, user_names) as.nameglue::glue('{user_names} = {deparse(args)}')),
                            args = user_args,
                            user_names = user_names)
  
  names(args_from_users) <- NULL
  
  args_from_users
}





Created on 2024-07-13 with reprex v2.1.0

Спасибо, но ваш fun2() не дает такого же результата, как fun1(). Yours возвращает именованный список, в котором часть a= является именем, а не присваиванием внутри самого выражения. (Кроме того, я отредактировал свой первоначальный ответ, указав, что в этом приложении мне нужна только база R. Извините за это!)

Vincent 13.07.2024 14:14

Я думаю, что это fun2() дает тот же результат, что и fun1(), и в этом проблема. Чтобы получить показанный здесь результат, вам просто нужен исходный `as.list(substitute(list(...)))[-1L]`.

user2554330 13.07.2024 19:17

@Винсент понял, не волнуйся! Я обновил свой ответ, включив в него решение, соответствующее ожидаемому результату.

Josh Allen 13.07.2024 22:44

Извините, но мне кажется, что сейчас хуже. Теперь вы возвращаете вещи с такими именами, как a = 2. Это не должно быть имя! это должно быть выражение. Честно говоря, я думаю, что оригинал Винсента as.list(substitute(list(...)))[-1L] — лучшее решение на данный момент, лучше, чем ваше, лучше, чем мое.

user2554330 14.07.2024 00:39

Ах, я понимаю, что ты имеешь в виду! По сути, если бы мы захотели, мы могли бы взять его из списка, и он оценит его позже. Я допустил ошибку, сохранив элементы в списке как символы, соответствующие выводу в консоли, но не желаемому результату. Извините, что засорил этим все уведомления! Хотя работать было весело

Josh Allen 14.07.2024 01:39

Другие вопросы по теме