Я думаю, что важно различать guish между литеральными значениями (константами) и неоцененными выражениями. Например, quos( b=2, c=3 )
всегда будет иметь значение 2 и 3, независимо от контекста. В таких случаях вам не нужно, чтобы они были выражениями или выражениями, и подойдет простой список значений. Затем вы можете использовать purrr::lift
, чтобы преобразовать любую произвольную функцию из числа ...
в список. Нет !!!
необходимо:
arglist <- list( replace=TRUE, size=5, x=1:10 ) # Note: list, not quos
sample2 <- purrr::lift(sample)
sample2( arglist ) # Same as sample( x=1:10, size=5, replace=TRUE)
# [1] 7 3 10 8 3
Неоцененные выражения вступают в игру, когда вы хотите сослаться на переменные или столбцы, которые, возможно, еще не были определены. В таких случаях вы можете воспользоваться rlang::list2()
для захвата списков аргументов, сращенных с помощью !!!
:
subset2 <- function( x, ... )
rlang::eval_tidy(rlang::expr(subset( {{x}}, !!!rlang::list2(...) )))
# Capture expressions because mpg and cyl are undefined at this point
argexpr <- rlang::exprs( mpg < 15, select=cyl )
# base::subset() doesn't support !!!, but our new function does!
subset( mtcars, !!!argexpr ) # Error in !argexpr : invalid argument type
subset2( mtcars, !!!argexpr ) # Same as subset( mtcars, mpg < 15, select=cyl )
mtcars %>% subset2(!!!argexpr) # Also works with the pipe
# cyl
# Duster 360 8
# Cadillac Fleetwood 8
# ...
. В приведенном выше примере subset2()
создает выражение subset( x, arg1, arg2, etc. )
«вручную», затем оценивает это. Оператор curly-curly используется в качестве ярлыка для !!enquo(x)
для вставки пользовательского выражения непосредственно в конечное выражение, тогда как rlang::list2()
расширяет и объединяет все остальные аргументы. Используя rlang::list2()
вместо base:list()
, мы добавляем поддержку !!!
для функции в целом.
Также стоит выделить rlang::exec()
и rlang::call2()
, которые являются тидивверсальными эквивалентами do.call
и call
от базы. Оба предлагают бесшовную поддержку объединения аргументов с !!!
:
rlang::exec( sample, !!!arglist )
eval(rlang::call2( subset, mtcars, !!!argexpr ))
Наконец, @Moody_Mudskipper имеет очень хороший пакет наречий / тегов . Один из этих тегов добавляет поддержку NSE для любой произвольной функции и имеет полную интеграцию с %>%
:
library(tags) ## installed with devtools::install_github("moodymudskipper/tags")
using_bang$sample( !!!arglist )
using_bang$subset( mtcars, !!!argexpr )
mtcars %>% using_bang$subset( !!!argexpr )