将R中的任意函数列表组合成新函数[元编程]

时间:2019-01-07 22:55:07

标签: r function metaprogramming

我想获取函数的任意列表,每个函数都带有一个参数,然后将它们变成依次运行每个组成函数的一个大函数。

例如,让我们看一下采用单个参数的三个函数(fgh)。我想像这样将它们作为参数提供给函数组合器:

function_maker(f,g,h)

并输出以下功能:

function(x) {
  f(x)
  g(x)
  h(x)
}

那怎么办?作为参数提供的函数不会彼此“交互”,我只希望它们按顺序运行,而新函数返回的最终值是按该顺序求值所返回的值。

我主要担心的是保持所有环境等正确无误,以使新创建的函数可以在调用的任何环境中工作。

到目前为止,这是我所拥有的,但是我怀疑它非常脆弱:

f <- function(x) {
  print("this is f")
  x + 2
}
g <- function(x) {
  print("this is g")
  x + 4
}
h <- function(x) {
  print("this is h")
  x + 9
}

function_maker <- function(...) {
  l <- rlang::enexprs(...) %>%
    purrr::map(~substitute(zzzz(cond), c(zzzz=.)))
  e <- rlang::expr({!!!l})
  e <- rlang::expr(function(cond) !!e)
  rlang::eval_tidy(e)
}

fgh <- function_maker(f,g,h)
body(fgh)
fgh(2)

1 个答案:

答案 0 :(得分:0)

这似乎可以完成工作:

function_maker <- function(...) {
  ret  <- function(x) {}
  for(f in list(...)) {
    n <- length(body(ret))
    body(ret)[(n+1):(n + length(body(f)) - 1)] <- body(f)[-1]
  }
  ret
}

结果:

> function_maker(f, g, h)
function (x)
{
    print("this is f")
    x + 2
    print("this is g")
    x + 4
    print("this is h")
    x + 9
}

或者更简单一些:

function_maker <- function(...) {
  calls <- mapply(function(x) paste0(x, "(x)"), as.list(substitute(list(...)))[-1])
  as.call(c(as.name("{"), parse(text=calls)))
}

这将导致:

> function_maker(f,g,h)
{
    f(x)
    g(x)
    h(x)
}