这是对这里讨论的扩展。
我们的三个部分需要是一个参数列表、一个主体和一个环境。
对于环境,我们将简单地env = parent.frame()
默认使用。
我们并不真正想要一个常规的旧列表作为参数,所以我们使用alist
它有一些不同的行为:
“......不评估值,并且允许没有值的标记参数”
args <- alist(a = 1, b = 2)
对于body,我们quote
的表达式得到一个call
:
body <- quote(a + b)
一种选择是转换args
为配对列表,然后简单地function
使用以下方法调用该函数eval
:
make_function1 <- function(args, body, env = parent.frame()) {
args <- as.pairlist(args)
eval(call("function", args, body), env)
}
另一种选择是创建一个空函数,然后用所需的值填充它:
make_function2 <- function(args, body, env = parent.frame()) {
f <- function() {}
formals(f) <- args
body(f) <- body
environment(f) <- env
f
}
第三种选择是简单地使用as.function
:
make_function3 <- function(args, body, env = parent.frame()) {
as.function(c(args, body), env)
}
最后,这对我来说似乎与第一种方法非常相似,除了我们使用稍微不同的习惯用法来创建函数调用,使用
substitute
而不是call
:
make_function4 <- function(args, body, env = parent.frame()) {
subs <- list(args = as.pairlist(args), body = body)
eval(substitute(`function`(args, body), subs), env)
}
library(microbenchmark)
microbenchmark(
make_function1(args, body),
make_function2(args, body),
make_function3(args, body),
make_function4(args, body),
function(a = 1, b = 2) a + b
)
Unit: nanoseconds
expr min lq median uq max
1 function(a = 1, b = 2) a + b 187 273.5 309.0 363.0 673
2 make_function1(args, body) 4123 4729.5 5236.0 5864.0 13449
3 make_function2(args, body) 50695 52296.0 53423.0 54782.5 147062
4 make_function3(args, body) 8427 8992.0 9618.5 9957.0 14857
5 make_function4(args, body) 5339 6089.5 6867.5 7301.5 55137