Вот ключевой фрагмент головоломки:
f <- function(x,data=NULL) {
eval(match.call()$x,data) # this is mtcars$hp, so just take the mean of it or whatever
}
> f(hp,mtcars)
[1] 110 110 93 110 175 105 245 62 95 123 123 180 180 180 205 215 230 66 52 65 97 150 150 245 175 66
[27] 91 113 264 175 335 109
# it even works without a data.frame specified:
> f(seq(10))
[1] 1 2 3 4 5 6 7 8 9 10
См. Ссылку @ Андри на документ @ Хэдли для объяснения того, почему это работает. См. Примечание @ Hadley о критическом предупреждении: f () не может быть запущен из другой функции.
В основном R использует ленивую оценку (например, он не оценивает вещи, пока они не используются). Таким образом, вы можете избежать передачи hp
, потому что он остается неоцененным символом, пока не появится где-нибудь. Поскольку match.call
берет его как символ и ждет, чтобы оценить его, все хорошо.
Затем eval
оценивает его в указанной среде. Согласно ?eval
, второй аргумент представляет:
Среда, в которой должен быть вычислен expr. Может также быть NULL,
list, фрейм данных, pairlist или целое число, как указано в sys.call.
Следовательно, вы в хорошей форме либо с NULL (если вы не передаете data.frame), либо с data.frame.
Доказательством ленивых вычислений является то, что это не возвращает ошибку (поскольку x никогда не используется в функции):
> g <- function(x) {
+ 0
+ }
> g(hp)
[1] 0