Mik*_*gan 5 r metaprogramming function
假设我有一个代表函数名称的“symbol”类型的对象。例如:
nm <- quote(mean)
Run Code Online (Sandbox Code Playgroud)
我想构造一个函数f,其主体使用由符号 命名的函数nm。例如:
f <- function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = mean(x), nothing = x)
}
Run Code Online (Sandbox Code Playgroud)
我想以相同的方式构造这个函数,这意味着我不会满意以下方法:
factory <- function(name) {
func <- match.fun(name)
function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = func(x), nothing = x)
}
}
g <- factory(nm)
Run Code Online (Sandbox Code Playgroud)
因为身体g不是body(f),环境g也不是environment(f)。
我考虑过的一种方法是bquote:
h <- eval(bquote({
function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = .(nm)(x), nothing = x)
}
}))
Run Code Online (Sandbox Code Playgroud)
bquote让我明白了大部分内容,但一个问题是 的print输出h不包含nm默认情况下的替换值:
h
## function(x, do = c("something", "nothing")) {
## switch(match.arg(do), something = .(nm)(x), nothing = x)
## }
print(h, useSource = FALSE)
## function (x, do = c("something", "nothing"))
## {
## switch(match.arg(do), something = mean(x), nothing = x)
## }
Run Code Online (Sandbox Code Playgroud)
原因似乎是srcref以下属性h:
identical(f, h)
## [1] TRUE
identical(f, h, ignore.srcref = FALSE)
## [1] FALSE
Run Code Online (Sandbox Code Playgroud)
我的问题是:如何解决f从构建的一般问题nm?
我对构造函数的条件h是identical(f, h)应该是TRUE并且 的输出print(h)应该包含 的替换值nm,类似于print(f)。
我欢迎改进我现有bquote方法的答案,或者建议新方法的答案,或者解释为什么我想做的事情实际上不可能的答案......
通读一遍?srcref,似乎有两种惯用的方法可以改进该bquote方法。第一个用于removeSource递归清理保留其源代码的函数:
h <- removeSource(eval(bquote({
function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = .(nm)(x), nothing = x)
}
})))
h
Run Code Online (Sandbox Code Playgroud)
function (x, do = c("something", "nothing"))
{
switch(match.arg(do), something = mean(x), nothing = x)
}
Run Code Online (Sandbox Code Playgroud)
第二个避免完全保留源代码:
op <- options(keep.source = FALSE)
h <- eval(bquote({
function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = .(nm)(x), nothing = x)
}
}))
options(op)
h
Run Code Online (Sandbox Code Playgroud)
function (x, do = c("something", "nothing"))
{
switch(match.arg(do), something = mean(x), nothing = x)
}
Run Code Online (Sandbox Code Playgroud)
实际上,?options声明 的默认值为keep.source,interactive()因此这两种方法在非交互式上下文中都有些多余。