43

Hadley Wickhamは最近、 r-devel メーリングリストで興味深い質問をしました。StackOverflow のトピックに関する既存の質問を見つけることができませんでした。

言い換えると:

R 関数は、引数リスト、本体、および環境の 3 つの要素で構成されます。これら 3 つの要素からプログラムで関数を構築できますか?

(かなり包括的な回答は、上記の r-devel リンクのスレッドの最後にあります。他の人がさまざまなソリューション自体のベンチマークを再作成し、回答として提供できるように、これを開いたままにしますが、必ず Hadley を引用してください。数時間以内に誰もステップアップしない場合は、私が自分でステップアップします.)

4

4 に答える 4

52

これは、ここでの議論の拡張です。

3 つの部分は、引数リスト、本体、および環境である必要があります。

環境については、デフォルトで単純に使用env = parent.frame()します。

引数に通常の古いリストは必要ないので、代わりに、alist 動作が異なる whichを使用します。

「...値は評価されず、値のないタグ付き引数は許可されます」

args <- alist(a = 1, b = 2)

ボディについては、次quoteの式を取得しcallます。

body <- quote(a + b)

1 つのオプションは、ペアリストに変換してから、以下を 使用してargs単純に関数を呼び出すことです。functioneval

make_function1 <- function(args, body, env = parent.frame()) {
      args <- as.pairlist(args)
      eval(call("function", args, body), env)
}

もう 1 つのオプションは、空の関数を作成してから、必要な値を入力することです。

make_function2 <- function(args, body, env = parent.frame()) {
      f <- function() {}
      formals(f) <- args
      body(f) <- body
      environment(f) <- env

      f
}

3 番目のオプションは、次のように単純に使用すること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
于 2012-10-19T23:56:22.297 に答える