16

次の単純な関数について考えてみます。

f <- function(x, value){print(x);print(substitute(value))}

引数xは最終的にによって評価されますprintが、value決して評価されません。したがって、次のような結果を得ることができます。

> f(a, a)  
Error in print(x) : object 'a' not found  
> f(3, a)  
[1] 3  
a  
> f(1+1, 1+1)  
[1] 2  
1 + 1  
> f(1+1, 1+"one")  
[1] 2  
1 + "one"

期待通りのすべて。

ここで、置換関数で同じ関数本体を検討します。

'g<-' <- function(x, value){print(x);print(substitute(value))}

(一重引用符は派手な引用符である必要があります)

試してみよう:

> x <- 3  
> g(x) <- 4  
[1] 3  
[1] 4  

これまでのところ珍しいことはありません...

> g(x) <- a  
Error: object 'a' not found  

これは予想外です。名前aは言語オブジェクトとして印刷する必要があります。

> g(x) <- 1+1  
[1] 4  
1 + 1  

xの以前の値はですので、これは問題ありません4。式が未評価で渡されたことに注意してください。

最終テスト:

> g(x) <- 1+"one"  
Error in 1 + "one" : non-numeric argument to binary operator  

ちょっと待ってください...なぜこの式を評価しようとしたのですか?

問題は、バグか機能かということです。ここで何が起こっているのですか?一部の教祖ユーザーがRの約束と遅延評価について光を当ててくれることを願っています。あるいは、それはバグであると結論付けるかもしれません。

4

3 に答える 3

12

問題を少し単純な例に減らすことができます。

g <- function(x, value)
'g<-' <- function(x, value) x
x <- 3

# Works
g(x, a)
`g<-`(x, a)

# Fails
g(x) <- a

これは、Rが置換関数を評価するときに何か特別なことをしていることを示唆しています。つまり、すべての引数を評価しているのではないかと思います。理由はわかりませんが、Cコードのコメント(https://github.com/wch/r-source/blob/trunk/src/main/eval.c#L1656およびhttps://github.com /wch/r-source/blob/trunk/src/main/eval.c#L1181)は、他の中間変数が誤って変更されていないことを確認することをお勧めします。

Luke Tierneyは、現在のアプローチの欠点について長いコメントをしており、置換関数を使用できるより複雑な方法のいくつかを示しています。

ここでのアプローチには2つの問題があります。

のような複雑な割り当て内の複雑な割り当てにより f(x, y[] <- 1) <- 3、外部割り当ての値の一時変数が上書きされてから、内部割り当てによって削除される可能性があります。これは、複数の一時変数を使用するか、RHSで行われるようにこの変数のpromiseを使用することで対処できます。エラーメッセージでの置換関数呼び出しの出力は、調整が必要になる場合があります。

フォームの割り当てを使用するとf(g(x, z), y) <- w、の値がz2回計算されます。1回g(x, z) は置換関数の呼び出し用で、もう1回は置換関数の呼び出し用ですg<-。promiseを使用することでこれに対処できる可能性があります。より多くの一時的なものを使用すると、置換および/または非標準の評価を使用する置換関数が台無しになるため、機能しません(そして、それを行うパッケージがあります-igraphは1つです)。

于 2013-03-06T22:27:44.833 に答える
8

キーは、このコメントの1682行目"eval.c"から始まる可能性があると思います(直後に代入演算のRHSの評価が続きます)。

/* It's important that the rhs get evaluated first because
assignment is right associative i.e. a <- b <- c is parsed as
a <- (b <- c). */

PROTECT(saverhs = rhs = eval(CADR(args), rho));

を実行すると、とg(x) <- a <- b <- 4 + 5の両方に値が割り当てられるaと予想されます。これは実際に起こることです。b9

どうやら、Rがこの一貫した動作を保証する方法は、残りの割り当てを実行する前に、常に最初に割り当てのRHSを評価することです。その評価が失敗した場合(のようなものを試した場合などg(x) <- 1 + "a")、エラーがスローされ、割り当ては行われません。

于 2013-03-07T07:00:40.263 に答える
4

ここで手足に出かけるので、知識のある方はお気軽にコメント・編集してください。

実行するときは注意してください

'g<-' <- function(x, value){print(x);print(substitute(value))}
x <- 1
g(x) <- 5

副作用は、5がに割り当てられることxです。したがって、両方を評価する必要があります。しかし、その後実行すると

'g<-'(x,10)

xと10の両方の値が出力されますが、の値はx同じままです。

投機:

g<-したがって、パーサーは、実際の割り当てを行う過程で呼び出すかどうかと、単に直接呼び出す場合を区別していますg<-

于 2013-03-06T17:13:05.157 に答える