我希望能够找到...
调用的(点)参数源自的环境。
设想
例如,考虑一个函数
foo <- function(x, ...) {
# do something
}
我们想要一个env_dots()
从内部调用的函数,它可以在对的调用foo()
中找到 的原始环境,即使对 的调用是深度嵌套的。也就是说,如果我们定义...
foo()
foo()
foo <- function(x, ...) {
# find the originating environment of '...'
env <- env_dots()
# do something
}
并嵌套一个对 的调用foo
,就像这样,
baz <- function(...) {
a <- "You found the dots"
bar(1, 2)
}
bar <- function(...)
foo(...)
那么调用baz()
应该返回...
in (嵌套)调用foo(...)
发起的环境:这是进行调用的环境bar(1, 2)
,因为2
(而不是1
)被传递给foo
. 特别是,我们应该得到
baz()$a
#> [1] "You found the dots"
天真的实现env_dots()
Update —env_dots()
在这里定义的一般不会起作用,因为 final...
可能由在调用堆栈的多个级别调用的参数填充。
这是一种可能性env_dots()
:
# mc: match.call() of function from which env_dots() is called
env_dots <- function(mc) {
# Return NULL if initial call invokes no dots
if (!rlang::has_name(mc, "...")) return(NULL)
# Otherwise, climb the call stack until the dots origin is found
stack <- rlang::call_stack()[-1]
l <- length(stack)
i <- 1
while (i <= l && has_dots(stack[[i]]$expr)) i <- i + 1
# return NULL if no dots invoked
if (i <= l) stack[[i + 1]]$env else NULL
}
# Does a call have dots?
has_dots <- function(x) {
if (is.null(x))
return(FALSE)
args <- rlang::lang_tail(x)
any(vapply(args, identical, logical(1), y = quote(...)))
}
这似乎有效:与
foo <- function(x, ...)
env_dots(match.call(expand.dots = FALSE))
我们得到
baz()$a
#> [1] "You found the dots"
bar(1, 2) # 2 gets passed down to the dots of foo()
#> <environment: R_GlobalEnv>
bar(1) # foo() captures no dots
#> NULL
问题
上面的实现env_dots()
效率不是很高。
env_dots()
在rlang和/或base R中是否有更巧妙的实现方式?如何将match.call()
调用移至 insideenv_dots()
?match.call(sys.function(-1), call = sys.call(-1), expand.dots = FALSE)
确实会起作用。
备注— 无法从 中推断点的起源环境rlang::quos(...)
,因为某些 quosures 不会被赋予调用环境(例如,当表达式是文字对象时)。