使用“bquote”(或替代方法)从符号构造函数

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

我对构造函数的条件hidentical(f, h)应该是TRUE并且 的输出print(h)应该包含 的替换值nm,类似于print(f)

我欢迎改进我现有bquote方法的答案,或者建议新方法的答案,或者解释为什么我想做的事情实际上不可能的答案......

Mik*_*gan 1

通读一遍?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.sourceinteractive()因此这两种方法在非交互式上下文中都有些多余。