是否可以检索函数调用的函数组件?也就是说,是否可以as.list(match.call())在另一个函数调用上使用。
背景是,我想要一个接受函数调用并返回所述函数调用的组件的函数。
get_formals <- function(x) {
# something here, which would behave as if x would be a function that returns
# as.list(match.call())
}
get_formals(mean(1:10))
# expected to get:
# [[1]]
# mean
#
# $x
# 1:10
Run Code Online (Sandbox Code Playgroud)
预期的结果是有get_formals回报match.call()是附带的函数调用中调用。
mean2 <- function(...) {
as.list(match.call())
}
mean2(x = 1:10)
# [[1]]
# mean2
#
# $x
# 1:10
Run Code Online (Sandbox Code Playgroud)
这个问题背后的动机是检查memoised 函数是否已经包含缓存值。memoise具有该功能,has_cache()但需要以特定方式调用has_cache(foo)(vals),例如,
library(memoise)
foo <- function(x) mean(x)
foo_cached <- memoise(foo)
foo_cached(1:10) # not yet cached
foo_cached(1:10) # cached
has_cache(foo_cached)(1:10) # TRUE
has_cache(foo_cached)(1:3) # FALSE
Run Code Online (Sandbox Code Playgroud)
我的目标是记录一些函数调用是否被缓存。
cache_wrapper <- function(f_call) {
is_cached <- has_cache()() # INSERT SOLUTION HERE
# I need to deconstruct the function call to pass it to has_cache
# basically
# has_cache(substitute(expr)[[1L]])(substitute(expr)[[2L]])
# but names etc do not get passed correctly
if (is_cached) print("Using Cache") else print("New Evaluation of f_call")
f_call
}
cache_wrapper(foo_cached(1:10))
#> [1] "Using Cache" # From the log-functionality
#> 5.5 # The result from the function-call
Run Code Online (Sandbox Code Playgroud)
你可以match.call()用来做参数匹配。
get_formals <- function(expr) {
call <- substitute(expr)
call_matched <- match.call(eval(call[[1L]]), call)
as.list(call_matched)
}
get_formals(mean(1:10))
# [[1]]
# mean
#
# $x
# 1:10
library(ggplot2)
get_formals(ggplot(mtcars, aes(x = mpg, y = hp)))
# [[1]]
# ggplot
#
# $data
# mtcars
#
# $mapping
# aes(x = mpg, y = hp)
library(dplyr)
get_formals(iris %>% select(Species))
# [[1]]
# `%>%`
#
# $lhs
# iris
#
# $rhs
# select(Species)
Run Code Online (Sandbox Code Playgroud)
编辑: 感谢@KonradRudolph 的建议!
上面的函数找到了正确的函数。它将在 的父级范围内搜索get_formals(),而不是在调用者的范围内搜索。更安全的方法是:
get_formals <- function(expr) {
call <- substitute(expr)
call_matched <- match.call(eval.parent(bquote(match.fun(.(call[[1L]])))), call)
as.list(call_matched)
}
Run Code Online (Sandbox Code Playgroud)
的match.fun()是由相同名称的非功能对象遮挡的正确解析功能重要。例如,如果mean被向量覆盖
mean <- 1:5
Run Code Online (Sandbox Code Playgroud)
第一个例子get_formals()会报错,而更新后的版本运行良好。