3

私のR開発では、オブジェクトのメソッドが呼び出されたprotoときに多数の引数を関数に自動的に渡すことができるように、関数プリミティブをオブジェクトにラップする必要があります。$perform()関数の呼び出しは、内部で。を介して行われdo.call()ます。関数が、それが定義されているクロージャから変数にアクセスしようとする場合を除いて、すべてが順調です。その場合、関数は名前を解決できません。

これは、動作を再現する私が見つけた最小の例です。

library(proto)

make_command <- function(operation) {
  proto(
    func = operation,
    perform = function(., ...) {
      func <- with(., func) # unbinds proto method
      do.call(func, list(), envir=environment(operation))
    }  
    )
}

test_case <- function() {
  result <- 100  
  make_command(function() result)$perform()
}

# Will generate error:
# Error in function ()  : object 'result' not found
test_case()

再現性のあるtestthatテストがあり、多くの診断出力も出力されます。診断出力は私を困惑させました。親環境チェーンを検索することにより、関数内にある私の診断コードは、関数が検出できないのとまったく同じ変数を検出して出力します。この要点を参照してください。

do.callの環境を正しく設定するにはどうすればよいですか?

4

2 に答える 2

3

これは、ポスターとオフラインで話し合った後の最終的な回答です。

make_command <- function(operation) {
 proto(perform = function(.) operation())
}
于 2012-06-20T23:55:32.547 に答える
1

ここでの問題は、次の場合、より明確で調査しやすいと思います。

  • 内の匿名関数make_command()を名前付き関数に置き換えます。

  • その関数が a を開くようにしますbrowser()( を取得しようとする代わりにresult)。そうすれば、自分がどこにいるのか、何が起こっているのかを確認することができます。

これを試してみてください。これにより、問題の原因が明確になります。

test_case <- function() {
  result <- 100  
  myFun <- function() browser()
  make_command(myFun)$perform()
}
test_case()
## Then from within the browser:
#
parent.env(environment())
# <environment: 0x0d8de854>
# attr(,"class")
# [1] "proto"       "environment"
get("result", parent.env(environment()))
# Error in get("result", parent.env(environment())) : 
#   object 'result' not found
#
parent.frame()
# <environment: 0x0d8ddfc0>
get("result", parent.frame())  ## (This works, so points towards a solution.)
# [1] 100

これが問題です。を評価していると思いますがmyFun()、その環境は の評価フレームですがtest_case()、 への呼び出しdo.call(func, ...)は実際には を評価してfunc()おり、その環境はprotoそれが定義された環境です。result独自のフレームで検索して見つからなかった後、 への呼び出しfunc()は字句スコープの規則に従い、次にproto環境を検索します。この環境にもその親環境にも という名前のオブジェクトが含まれていないresultため、エラー メッセージが表示されます。

これがすぐに意味をなさない場合は、ブラウザ内をいじり続けることができます。以下に、役立つと思われるその他の呼び出しをいくつか示します。

environment(get("myFun", parent.frame()))
ls(environment(get("myFun", parent.frame())))
environment(get("func", parent.env(environment())))
ls(environment(get("func", parent.env(environment()))))
于 2012-06-20T04:52:51.737 に答える