既に評価中の約束:再帰的なデフォルト引数参照または以前の問題?


143

これが私のRコードです。関数は次のように定義されます。

f <- function(x, T) {
  10 * sin(0.3 * x) * sin(1.3 * x ^ 2) + 0.001 * x ^ 3 + 0.2 * x + 80
}

g <- function(x, T, f=f) {
  exp(-f(x) / T)
}

test <- function(g=g, T=1) { 
  g(1, T)
}

実行エラーは次のとおりです。

> test()test()の
エラー:
既に評価中の約束:再帰的なデフォルト引数参照または以前の問題?

私はの定義に置き換えた場合fのものでg、その後、エラーが表示されなくなります。

エラーは何だったのだろうと思っていましたか?の定義を置き換えない場合の修正方法fg?ありがとう!


更新:

ありがとう!2つの質問:

(1)関数testがの引数をさらに取るf場合、次のようなものを追加しtest <- function(g.=g, T=1, f..=f){ g.(1,T, f.=f..) }ますか?より多くの再帰がある場合、それを追加することは良い安全な方法です。

(2)とのようfな非関数の引数である場合g <- function(x, T, f=f){ exp(-f*x/T) }test <- function(g.=g, T=1, f=f){ g.(1,T, f=f.) }正式な非関数の引数と実際の非関数の引数の両方に同じ名前を使用することは適切で安全な方法でしょうか、それとも潜在的な問題を引き起こす可能性がありますか?

回答:


159

フォームの正式な引数がx=x原因です。発生する2つのインスタンスを排除すると、次のようになります。

f <- function(x, T) {
   10 * sin(0.3 * x) * sin(1.3 * x^2) + 0.001 * x^3 + 0.2 * x + 80 
}

g <- function(x, T, f. = f) {  ## 1. note f.
   exp(-f.(x)/T) 
}

test<- function(g. = g, T = 1) {  ## 2. note g.
   g.(1,T) 
}

test()
## [1] 8.560335e-37

2
ありがとう!2つの質問(1)関数testがさらにfの引数を取る場合、test <-function(g。= g、T = 1、f .. = f){g。(1、T、f。 = f ..)}?より多くの再帰がある場合、それを追加することは良い安全な方法です。?(2)fが関数以外の引数の場合、たとえばg <-function(x、T、f = f){exp(-f x / T)} *およびtest <-function(g。= g、T = 1、f = f){g。(1、T、f = f。)}、正式な引数と実際の非関数引数の両方に同じ名前を使用すると、適切で安全な方法になりますか、それとも問題が発生する可能性がありますか?
Tim

16
他の解決策はありますか?私はいくつかの引数を関数のチェーンのかなり下(約5レベル)に渡していますが、このソリューションはになる可能性があり.....cumbersomeます。:)
RomanLuštrik12年

2
@RomanLuštrik引数を渡していて、それらの一部を安全に無視できる場合は、楕円...またはリストを使用して、関数チェーンに引数を渡してください。すべてを事前に定義するよりも(善と悪のために)はるかに柔軟です。楕円(またはリスト)の元の引数が適切かどうかを確認するために、いくつかのチェックを追加する必要があるだけかもしれません。
russellpierce 2015

2
ここでの別のオプションは、アクティブなプロミスの偶発的な強制をバイパスして、親フレームで引数を見つけることを明示的に試みることget("f", envir = parent.frame())です。
Kevin Ushey 2016年

1
唯一の要件は、左側と右側で同じ名前を使用しないことです。それ以外はただのスタイルです。
G.グロタンディーク

13

引数評価コンテキストを指定すると、同じ名前の問題を回避できます。

f <- function(x) {
  10 * sin(0.3 * x) * sin(1.3 * x ^ 2) + 0.001 * x ^ 3 + 0.2 * x + 80
}
g <- function(x, t=1, f=parent.frame()$f) {
  exp(-f(x) / t)
}
test <- function(g=parent.frame()$g, t=1) { 
  g(1,t)
}
test()
[1] 8.560335e-37

2
これはより良い方法です、私は環境がより明確であることを明記すると思います
クラウドコンピューティング19/04/19

1

私はG. Grothendieckの回答が好きですが、次のように、関数のパラメーターに関数名を含めない方が簡単なのではないかと思いました。

f <- function(x, T) {
  10 * sin(0.3 * x) * sin(1.3 * x^2) + 0.001 * x^3 + 0.2 * x + 80 
}
g <- function(x, T) {
  exp(-f(x)/T) 
}
test<- function(T = 1) {
  g(1,T)
}
test()
## [1] 8.560335e-37

1

すでに述べたように、問題はそれ自体として定義された関数の引数を持つことから生じます。ただし、これが問題である理由の説明を追加したいと思います。理解することで、問題を回避するためのより簡単な(私にとっての)方法が得られたためです。定義の代わりに呼び出しで引数を指定するだけです。

これは動作しません:

x = 4
my.function <- function(x = x){} 
my.function() # recursive error!

しかしこれはうまくいきます:

x = 4
my.function <- function(x){} 
my.function(x = x) # works fine!

関数の引数は、独自のローカル環境に存在します。

Rはまずローカル環境で変数を探し、次にグローバル環境で探します。これは、関数内で変数がグローバル環境の変数と同じ名前を持つことができるのと同じで、Rはローカル定義を使用します。

関数の引数定義が独自のローカル環境を形成するため、次のような他の引数値に基づいてデフォルトの引数値を持つことができます

my.function <- function(x, two.x = 2 * x){}

そのため、関数を定義することはできませんmy.function <- function(x = x){}が、を使用して関数を呼び出すことができますmy.function(x = x)。関数を定義すると、Rは引数x =をのローカル値として検出するので混乱xしますが、関数を呼び出すと、R x = 4は呼び出し元のローカル環境で検出されます。

したがって、引数名を変更するか、他の回答で述べたように明示的に環境を指定してエラーを修正することに加えてx=x、関数を定義するときではなく、呼び出すときにそれを指定することもできます。私にとってx=xは、呼び出しでそれを指定することが最善の解決策でした。これは、余分な構文や変数名の蓄積が増えないためです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.