Объединение произвольного списка функций в R в новую функцию [метапрограммирование] - PullRequest
0 голосов
/ 08 января 2019

Я хочу взять произвольный список функций, каждая из которых принимает один аргумент, и превратить их в одну большую функцию, которая выполняет каждую составляющую функцию, одну за другой, по порядку.

Например, давайте рассмотрим три функции (f, g, h), которые принимают один аргумент. Я хочу предоставить их в качестве аргументов моему объединителю функций следующим образом:

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 голосов
/ 08 января 2019

Это похоже на работу:

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)
}
...