Я не думаю, что ответ Джоша правильный.
Что ж, было бы правильно, если бы <-
было в стеке вызовов в вашем примере. Но это не так.
Небольшое резюме: при обычном вычислении функции R аргументы рассматриваются как обещания, которые лениво оцениваются при доступе. Это означает, что в следующем вызове:
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}},
Взгляните на четвертый аргумент: 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 раз (!!!) медленнее. Обычно это неприемлемо.
person
Konrad Rudolph
schedule
02.07.2017
<-
,log
иUseMethod
все являются примитивами, но по совершенно разным причинам. - person Josh O'Brien   schedule 25.10.2012.Internal
- person hadley   schedule 25.10.2012