如何以编程方式创建 R 函数? [英] How to create an R function programmatically?
问题描述
Hadley Wickham 最近在 r-devel mailing 列表,并且无法在 StackOverflow 上找到有关该主题的现有问题,我认为可能是有用的,因为它也存在于此.
Hadley Wickham recently asked an interesting question on the r-devel mailing list, and being unable to find an existing question on the topic on StackOverflow, I thought it might be useful for it exist here as well.
转述:
R 函数由三个元素组成:参数列表、主体和环境.我们可以从这三个元素中以编程方式构造一个函数吗?
(在上面的 r-devel 链接中的线程末尾找到了一个相当全面的答案.我将让其他人重新创建各种解决方案的基准测试并将其作为答案提供,但请确保如果你这样做,请引用哈德利.如果几个小时内没有人站出来,我会自己做.)
(A fairly comprehensive answer is reached at the end of the thread in the r-devel link above. I will leave this open for others to recreate the benchmarking of the various solutions themselves and supply it as an answer, but be sure to cite Hadley if you do. If no one steps up in a few hours I'll do it myself.)
推荐答案
这是对讨论的扩展 此处.
我们的三个部分需要是一个参数列表、一个主体和一个环境.
Our three pieces need to be an argument list, a body and an environment.
对于环境,我们将默认使用 env = parent.frame()
.
For the environment, we will simply use env = parent.frame()
by default.
我们真的不想要参数的常规旧列表,因此我们使用 alist
它有一些不同的行为:
We do not really want a regular old list for the arguments, so instead we use alist
which has some different behavior:
...不计算值,并且允许没有值的标记参数"
"...values are not evaluated, and tagged arguments with no value are allowed"
args <- alist(a = 1, b = 2)
对于主体,我们引用
我们的表达式以获得call
:
For the body, we quote
our expression to get a call
:
body <- quote(a + b)
一种选择是将 args
转换为一个pairlist,然后简单地调用函数 function
使用 eval
:
One option is to convert args
to a pairlist and then simply call the function function
using eval
:
make_function1 <- function(args, body, env = parent.frame()) {
args <- as.pairlist(args)
eval(call("function", args, body), env)
}
另一种选择是创建一个空函数,然后用所需的值填充它:
Another option is to create an empty function, and then fill it with the desired values:
make_function2 <- function(args, body, env = parent.frame()) {
f <- function() {}
formals(f) <- args
body(f) <- body
environment(f) <- env
f
}
第三种选择是简单地使用 as.function
:
A third option is to simply use as.function
:
make_function3 <- function(args, body, env = parent.frame()) {
as.function(c(args, body), env)
}
最后,这对我来说似乎与第一种方法非常相似,除了我们使用稍微不同的习惯用法来创建函数调用,使用substitute
而不是 call
:
And finally, this seems very similar to the first method to me, except
we are using a somewhat different idiom to create the function call, using
substitute
rather than 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
这篇关于如何以编程方式创建 R 函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!