Lazy Evaluation: Почему я не могу использовать график (..., xlim = c (0,1), ylim = xlim)?

Одна из R наибольшая особенность - ленивая оценка. Это приводит к часто встречаемому стилю, в котором аргументы могут использоваться как значение других аргументов. Например, в книге Хэдли, посвященной Advanced R, вы видите этот пример:

g <- function(a = 1, b = a * 2) {
  c(a, b)
}
g()
#> [1] 1 2
g(10)
#> [1] 10 20

Теперь я хотел бы сделать то же самое для графика с xlim и ylim, однако он не работает:

> plot(1, 1, ylim = c(0,1), xlim = ylim)
Error in plot.default(1, 1, ylim = c(0, 1), xlim = ylim) : 
  object 'ylim' not found
> plot(1, 1, xlim = c(0,1), ylim = xlim)
Error in plot.default(1, 1, xlim = c(0, 1), ylim = xlim) : 
  object 'xlim' not found
  • Кто-нибудь знает, почему?
  • Есть ли способ достичь этого?

Ответ 1

Цитата из хорошего руководства:

4.3.3 Оценка аргументов

Одна из самых важных вещей, которые нужно знать об оценке аргументы функции - это предоставленные аргументы и значения по умолчанию аргументы обрабатываются по-разному. Приведенные аргументы функции оцениваются в кадре оценки вызывающего функция. Аргументы по умолчанию для функции оцениваются в кадр оценки функции.

Чтобы понять, что это значит на практике, создайте функцию, в которой одно значение по умолчанию параметра является функцией другого значения аргумента:

f <- function(x=4, y=x^2) {
    y
}

Когда вызывается с y значением по умолчанию, R смотрит на оценку y в кадре оценки вызова функции, то есть в той же среде, в которой оценивается весь объект функции - место, где x было очень хорошо (и, конечно же, есть):

f() 
# [1] 16

Когда вызывается с поставляемым значением y, R смотрит в кадр оценки вызывающей функции (здесь глобальная среда), не находит x и позволяет вам знать это в его сообщение об ошибке:

f(y=x^2)
# Error in f(y = x^2) : object 'x' not found

Ответ 2

Здесь есть проблема. В выражении plot(1, 1, ylim = c(0,1), xlim = ylim) имя ylim доступно только как имя параметра и недоступно для вызывающего абонента в целом.

Для переменной, которая будет использоваться в правой части назначения, она должна быть доступна в области вызова.

Причина, по которой ваш первый пример работает, заключается в том, что вы записываете аргументы по умолчанию в свое определение функции, которое имеет доступ ко всем параметрам.

Один возможный обходной путь, который имеет смысл только в том случае, если это то же самое значение по умолчанию, которое вы хотите во многих случаях, заключается в том, чтобы обернуть функцию plot в новую функцию, которая имеет такое поведение.

myplot <- function(x, y, ylim, xlim = ylim,...) {
  plot(x,y, ylim = ylim, xlim = xlim,...)
}

myplot(1,1, ylim=c(0,1))