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

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

问题描述

Hadley Wickham 最近在 r-devel邮件列表,并且无法找到关于StackOverflow主题的现有问题,我认为它可能



解释:



R函数由三个要素:参数列表,正文和环境。我们可以通过这三个元素以编程方式构造一个函数吗?



(在上面的r-devel链接的线程结尾处达到了相当全面的答案。我会留给他人重新创建各种解决方案的基准并提供它作为答案,但如果你这样做,一定要引用Hadley。如果没有人在几个小时内提高,我会自己做。 ) 这是对讨论的扩展 here



我们的三件作品需要一个参数列表,一个body和一个环境。

对于环境,我们将默认使用 env = parent.frame()

我们并不是真的需要一个常规的旧参数列表,所以我们使用 alist
有一些不同的行为:


... va



  args<  -  

alist(a = 1,b = 2)

对于正文,我们 c> body< - quote(a + b)

一个选项是将 args 给一个pairlist,然后使用 eval function
c>:

$ p $ 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
环境(f)< - env

f
}

第三种选择是简单地使用 as.function

  make_function3< ;函数(args,body,env = parent.frame()){
as.function(c(args,body),env)
}

最后,这对我来说看起来非常类似于第一种方法,除了
我们使用了不同的成语来创建函数调用,使用
替代而不是调用

<$ (函数args,body,env = parent.frame()){
subs < - list(args = as.pairlist(args),body = body)
eval(替代(`function`(args,body),subs),env)
}


library(microbenchmark)
microbenchmark (
make_function1(args,body),
make_function2(args,body),
make_function3(args,body),
make_function4(args,body),
functi (a = 1,b = 2)a + b


单位:纳秒
expr min lq中值uq max
1函数(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(参数,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


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.

To paraphrase:

An R function consists of three elements: an argument list, a body and an environment. Can we construct a function programmatically from these three elements?

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

解决方案

This is an expansion on the discussion here.

Our three pieces need to be an argument list, a body and an environment.

For the environment, we will simply use env = parent.frame() by default.

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)

For the body, we quote our expression to get a call:

body <- quote(a + b)

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
}

A third option is to simply use as.function:

make_function3 <- function(args, body, env = parent.frame()) {
      as.function(c(args, body), env)
}

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天全站免登陆