В основном ваша проблема заключается в том, что когда вы вызываете enquos()
для одного параметра, вы также цитируете вызов list()
(который является одним вызовом). Итак, в основном вы создаете
filter_args_enquos <- quo(list(Sepal.Length > 5, Petal.Length > 5))
и при звонке
dplyr::filter(iris, !!!filter_args_enquos)
это то же самое, что и
dplyr::filter(iris, list(Sepal.Length > 5, Petal.Length > 5))
, который не является допустимым синтаксисом dplyr. !!!
должен работать с правильным спискообразным объектом, а не безоценочным вызовом списка, обратите внимание, что это будет работать
filter_args_enquos <- list(quo(Sepal.Length > 5), quo(Petal.Length > 5))
dplyr::filter(iris, !!!filter_args_enquos)
потому что здесь мы на самом деле оцениваем список и цитируем только то, что находится внутри списка. Это в основном тип объекта, созданного enquos при использовании ...
filter_wrap <- function(x, ...) {
filter_args_enquos <- rlang::enquos(...)
dplyr::filter(x, !!!filter_args_enquos)
}
filter_wrap(iris, Sepal.Length > 5, Petal.Length > 5)
Функция enquos()
ожидает несколько параметров, а не только один список. Вот почему он предназначен для использования с ...
, потому что это расширится до нескольких параметров. Если вы хотите передать список, вы можете написать вспомогательную функцию, которая может искать этот особый случай и правильно расширять предложение. Например
expand_list_quos <- function(x) {
expr <- rlang::quo_get_expr(x)
if (expr[[1]]==as.name("list")) {
expr[[1]] <- as.name("quos")
return(rlang::eval_tidy(expr, env = rlang::quo_get_env(x)))
} else {
return(x)
}
}
Тогда вы можете использовать его с
filter_wrap <- function(x, filter_args) {
filter_args <- expand_list_quos(rlang::enquo(filter_args))
dplyr::filter(x, !!!filter_args)
}
и оба они будут работать
filter_wrap(iris, Petal.Length > 5)
filter_wrap(iris, list(Sepal.Length > 5, Petal.Length > 5))
но это не совсем то, что этот enquo
материал «предназначен» для использования. Метод ...
гораздо более идиоматичен. Или вызовите quos()
явно, если вам нужно больше контроля
filter_wrap <- function(x, filter_args) {
dplyr::filter(x, !!!filter_args)
}
filter_wrap(iris, quo(Petal.Length > 5))
filter_wrap(iris, quos(Sepal.Length > 5, Petal.Length > 5))