我有一个函数fun_1
在其substitute()
参数上使用...
,另一个函数fun_2
使用签名fun_2(...)
来实现模式{{1} }}。我希望do.call(fun_1, dots)
内的fun_1()
看到fun_2()
传递给...
。这是我想要做的事情的例证。
fun_2()
我认为fun_1 <- function(...) {
substitute(list(...))[-1] %>%
sapply(deparse)
}
foo <- "X"
bar <- "Y"
fun_1(foo, bar)
# [1] "foo" "bar"
fun_2 <- function(...) {
# dots <- Filter(length, ???)
# rlang::invoke(my_fun, dots)
}
fun_2(foo, bar, NULL)
# desired output:
# [1] "foo" "bar"
有足够的魔力使这项工作成功但我无法弄清楚如何运作。只要
rlang
fun_1
可以访问fun_1()
和foo
bar
模式在do.call
编辑:我还需要fun_2()
才能工作
答案 0 :(得分:0)
我最终这样做了:
fun_1 <- function(...) {
substitute(list(...))[-1] %>%
sapply(deparse) %>%
gsub("~", "", .)
}
foo <- "X"
bar <- "Y"
fun_1(foo, bar)
# [1] "foo" "bar"
fun_2 <- function(...) {
nonempty <- rlang::dots_splice(...) %>%
sapply(Negate(rlang::is_empty)) %>%
which()
envir <- rlang::caller_env()
quosures <- rlang::dots_exprs(...) %>%
lapply(function(x) if (rlang::is_lang(x))
rlang::lang_tail(x) else x) %>%
unlist() %>%
lapply(rlang::new_quosure, env = envir) %>%
`[`(nonempty)
rlang::lang("fun_1", !!! quosures) %>%
rlang::eval_tidy()
}
fun_2(foo, bar, NULL)
# [1] "foo" "bar"
fun_2(list(foo, bar))
# [1] "foo" "bar"
fun_2(foo, list(bar))
# [1] "foo" "bar"
首先,我必须操纵传递给...
的表达式,然后使用正确的环境从中创建quosures,然后构建一个转发到fun_1
的调用。
答案 1 :(得分:0)
这是一种更简洁的方法:
library("purrr")
library("rlang")
quo_list <- function(quo) {
expr <- get_expr(quo)
if (is_lang(expr, "list")) {
args <- lang_args(expr)
map(args, new_quosure, env = get_env(quo))
} else {
list(quo)
}
}
fun2 <- function(...) {
quos <- quos(..., .ignore_empty = "all")
quos <- flatten(map(quos, quo_list))
fun1(!!! quos)
}
fun1 <- function(...) {
map(quos(...), quo_name)
}
然而,以这种方式解析表达式通常是个坏主意。这里实现的列表拼接只有在调用特别提到list()
时才会起作用,如果他们使用rlang::ll()
或者用户取消引用列表,或者在许多其他情况下,它们将不起作用。由于这不是一个tidyeval实现,你可能应该删除标签吗?