Reputation: 18612
Say I have two functions and I want to nest a
within b
:
library(dplyr)
library(rlang)
a <- function(var, values){
filter(iris, {{var}} %in% values)
}
a(Species, "virginica") %>% head()
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 6.3 3.3 6.0 2.5 virginica
2 5.8 2.7 5.1 1.9 virginica
3 7.1 3.0 5.9 2.1 virginica
4 6.3 2.9 5.6 1.8 virginica
5 6.5 3.0 5.8 2.2 virginica
6 7.6 3.0 6.6 2.1 virginica
b
calls a
, but uses the dot-dot-dot ...
for some other things. It has a list argument that is passed to a
:
b <- function(l, ...){
eval_tidy(expr(a(!!! l)))
}
b(l = list(var = quo(Species), values = "virginica")) %>% head() # works if user passes quosure
Can I pass a list of arguments to b
to be evaluated in a
when some of the elements need to be quoted? So the call to b
would look like the following:
b(l = list(var = Species, values = "virginica")) # does not work
I have tried the following, but it seems I need to split-splice one more time or something:
b <- function(l, ...){
l <- enquos(l)
qq_show(a(!!! l))
}
b(l = list(var = Species, values = "virginica"))
# a(^list(var = Species, values = "virginica"))
Other attempts result in premature evaluation of Species
and therefore the error: object 'Species' not found
.
Upvotes: 3
Views: 165
Reputation: 6803
Create a helper function that collects arguments for a()
. This helper can defuse var
with enquo()
so the user does not have to use quo()
.
a <- function(var, values) {
filter(iris, {{ var }} %in% values)
}
a_opts <- function(var, values) {
list(var = enquo(var), values = values)
}
Then b()
expects the user to pass a list of arguments presumably created with a_opts()
. But how do we pass these arguments to a()
? We can't use !!!
directly because splicing is only enabled in ...
(see dynamic dots) and a()
doesn't take ...
.
One solution is to use do.call()
. Another solution idiomatic to rlang is to enable !!!
explicitly with inject()
:
b <- function(l) {
inject(a(!!!l))
}
Example usage:
a_opts(Species, "virginica") %>%
b() %>%
head()
Upvotes: 1