Передать именованные параметры в функцию, которая вызывает функцию, которая не является mutate - PullRequest
2 голосов
/ 01 февраля 2020

Я пытаюсь сделать что-то очень похожее на здесь .

По сути, мне нужно передать именованный список функции и передать этот именованный список другой функции в качестве ее параметров. ,

Если мы перейдем по этой ссылке, они смогут сделать это с помощью mutate, и я могу повторить это:

df <- tribble(
    ~a,
    1
)

foo <- function(x, args) {
    mutate(x, !!! args)
}

foo(df, quos(b = 2, c = 3)

# A tibble: 1 x 3
      a     b     c
  <dbl> <dbl> <dbl>
1     1     2     3

Но если я попытаюсь сделать это с какой-либо другой функцией, она потерпит неудачу , Скажем, если я попытаюсь использовать print (первым параметром является x, поэтому я передаю именованный список с x):

print(x= "hello")
[1] "hello"

foo <- function(x, args) {
    print(!!! args)
}

foo(df, quos(x = "hello"))

Error in !args : invalid argument type

Я не уверен, почему это не будет работать за пределами «Тидиверс» функций. Я пробовал разные комбинации sym, enquo, bang bang, curly curly и др. c., Но безрезультатно.

Конечно, моей конечной целью является не использование печати, а использование другого пользователя. определенная функция на своем месте, так что если у вас есть какие-либо советы о том, как этого добиться, я также был бы очень признателен. (И, кстати, мне нужно использовать именованный список, я не думаю, что смогу использовать ...).

Большое спасибо за вашу помощь.

Ответы [ 3 ]

1 голос
/ 01 февраля 2020

Вам нужно blast(), что, вероятно, будет включено в rlang 0.5.0.

blast <- function(expr, env = parent.frame()) {
  rlang::eval_bare(rlang::enexpr(expr), env)
}

blast(cbind(!!!letters))
1 голос
/ 03 февраля 2020

Я думаю, что важно различать 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 )
0 голосов
/ 01 февраля 2020

Вы можете использовать match.call() внутри вашей функции, чтобы получить список аргументов и их имена:

myfun <- function(x, ...){
    args <- as.list(match.call())[-1]
    print(setNames(unlist(args), names(args)))
    lapply(match.call()[-1], class)
}

myfun(x=list(a=1, b="hi", c="a"), b=5)
#> $x
#> list(a = 1, b = "hi", c = "a")
#> 
#> $b
#> [1] 5
#> $x
#> [1] "call"
#> 
#> $b
#> [1] "numeric"
...