4

私はループ内の関数を定義していて、プライベート環境を持ち歩くことなくループ変数の評価を強制しようとしています。

例: 1、2、...、6を通過して次のような別の関数に渡される一連の関数handlers$h1、、handlers$h2... :handlers$h6

handlers <- list()
for (i in 1:6) {
    handlers[[paste0('h', i)]] <- function () {
        message(i) # <-- example
    }
}

したがってhandlers$h1()、メッセージ1、handlers$h2()メッセージ2、..。

代わりに、すべての関数6は、の現在の値であるを返しますi

これを回避するために、この質問で指定されているクロージャを使用できます

msg <- function(i) {
    force(i)
    function () { message(i) }
}

for (i in 1:6) {
    handlers[[paste0('h', i)]] <- msg(i)
}

これで、各関数は期待どおりに機能しますが、各関数は独自の環境を実行する必要があります。

handlers$h1
# function () { message(i) }
# <environment: 0x9342b80>

どうすればhandlers$h1印刷できるようにできますか?function () { message(1) }つまり、を評価iして定義に直接置き換え、環境の必要性をなくしますか?

私が考えることができる唯一の方法は次のとおりです。

  • 使用するeval(私がしたくないこと);
  • 1〜6を直接置き換えて、各定義を手動で書き出します(この場合、関数が6つしかない場合は問題ありませんが、一般にスケーラブルではありません)。
4

3 に答える 3

7

を使用するいくつかのアプローチがありますbody<-

あなたが使うことができますbquote

handlers <- list()

for (i in 1:6) {
  handlers[[paste0('h', i)]] <- function () {}
  body( handlers[[paste0('h', i)]]) <- bquote(message(.(i)))
}

handlers$h1
## function () 
##   message(1L)

またsubstitute

for (i in 1:6) {
  handlers[[paste0('h', i)]] <- function () {}
  body( handlers[[paste0('h', i)]]) <- substitute(message(i), list(i=i))
}
于 2013-03-26T01:39:17.483 に答える
3

残念ながら、ベースRには手作業で関数を作成する機能がありませんが、prirは次の機能を提供しmake_functionます。

library(pryr)

handlers <- list()
for (i in 1:6) {
  body <- substitute(message(i), list(i = i))
  f <- make_function(alist(), body)

  handlers[[paste0('h', i)]] <- f
}

substituteを使用して、引用符で囲まれた呼び出しを手動で変更することに注意してください。

pryrのもう1つのクールな(IMO!)関数はunenclose、です。これは、囲んでいる環境で定義された変数に代入することによって、関数を囲みません。

msg <- function(i) {
    force(i)
    function () message(i)
}
msg(1)
# function () message(i)
# <environment: 0x102dc6ca0>
unenclose(msg(1))
# function () 
# message(1)

しかし、実際には、元のクロージャーを使用することのマイナス面はありません。

于 2013-03-26T13:30:29.733 に答える
1

これが2つの方法です。それぞれの##行を除いて同じです。

フォーマル<-

handlers <- list()
f <- function() message(i)
for (i in 1:6) { 
   formals(f) <- list(i = i) ##
   handlers[[paste0('h', i)]] <- f 
}

痕跡

handlers <- list()
f <- function() message(i)
for (i in 1:6) { 
   trace(f, bquote(i <- .(i)), print = FALSE) ##
   handlers[[paste0('h', i)]] <- f 
}
于 2013-03-26T13:55:48.463 に答える