Joshの答えは正しくないと思います。
さて、あなたの例のコールスタックにあったならそれは正しいでしょう。しかし、そうではありません。<-
簡単な要約:通常のR関数の評価では、引数はアクセス時に遅延評価されるpromiseとして扱われます。これは、次の呼び出しで次のことを意味します。
foo(bar(baz))
bar(baz)
内部 で評価されますfoo
(あるとしても)。したがって、次のように、内部の呼び出しスタックを検査するとbar
、次のようになります。
bar = function (x) {
sys.calls()
}
…すると、次のようになります。
[[1]]
foo(bar(baz))
[[2]]
bar(baz)
残念ながら、ご指摘のとおり、<-
(および=
)は通常の関数ではなく、プリミティブ(BUILTINSXP
)です。実際、Rソースでは次のように定義されています。
{"<-", do_set, 1, 100, -1, {PP_ASSIGN, PREC_LEFT, 1}},
4番目の引数を見てください:100
。このコードの前のコメントは、数字の意味を説明しています。左端の数字を説明する関連部分は次のとおりです。
Z = 1は、(BUILTINSXP
)を呼び出す前に引数を評価すると言います
これは、次のコードの呼び出しが割り当ての前bar(baz)
に評価されることを意味します。
`<-`(x, bar(baz))
そのため<-
、リストに表示されませんsys.calls()
:現在の呼び出しではありません。bar
評価終了後に呼び出されます。
この制限を回避する方法があります。Rコードで<-
/を再定義できます。=
これを行うと、通常のR関数のように動作します。
`<-` = function (lhs, rhs) {
name = as.name(deparse(substitute(lhs), backtick = true))
rhs # evaluate expression before passing it to `bquote`, for a cleaner call stack
eval.parent(bquote(base::`<-`(.(name), .(rhs))))
}
ただし、これにより、再定義されたスコープ内の後続のすべての割り当てで無視できないパフォーマンスヒットが発生することに注意してください<-
。実際、割り当てはおよそ1000倍(!!!)遅くなります。これは通常受け入れられません。