如何以编程方式创建 R 函数? [英] How to create an R function programmatically?

查看:28
本文介绍了如何以编程方式创建 R 函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆