do.call и кривая не могут построить функцию внутри другой функциональной среды

Я столкнулся со странной проблемой, связанной с do.call и curve:

func1 <- function (m, n) {
  charac <- paste ("func2 <- function(x)", m, "*x^", n, sep = "")
  eval(parse(text = charac))
  return(func2)
}
func3 <- function (m, n) {
  my.func <- func1 (m, n)
  do.call("curve",list(expr = substitute(my.func)))
}

func1 строит func2, а func3 отображает сконструированный func2. Но когда я запускаю func3, будет отображаться следующая ошибка:

> func3 (3, 6)
Error in curve(expr = function (x)  : 
  'expr' must be a function, or a call or an expression containing 'x'

Однако, когда я запускаю func1 и рисую вывод вручную (без применения func3), func2 будет отображаться:

my.func <- func1 (3, 6)
do.call("curve",list(expr = substitute(my.func)))

То, что здесь произошло, приводит меня в замешательство, и я не знаю, почему do.call не может отображать func2 внутри локальной среды func3.

Спасибо


person Ehsan Masoudi    schedule 12.01.2013    source источник


Ответы (4)


Это проблема не do.call, а substitute , которые оцениваются по умолчанию в глобальной среде. Поэтому вам нужно указать, в какой среде должна происходить замена. Здесь, очевидно, в локальном окружении func3.

Это должно работать:

 do.call("curve",list(expr = substitute(my.func,
                                           env = parent.frame())))

Изменить спасибо Двин

Как сказано в комментарии, замените env Defaults на текущую среду оценки. Итак, почему приведенный ниже код работает? Ответ в хелпе substitute

формальный аргумент функции или явно созданный с помощью delayedAssign(), слот выражения обещания заменяет символ. Если это обычная переменная, подставляется ее значение, если только env не является .GlobalEnv, и в этом случае символ остается неизменным.

env = parent.frame(n=1) эквивалентно .GlobalEnv, поэтому символ (my.func) оставлен без изменений. Таким образом, правильным ответом будет:

do.call("curve",list(expr = substitute(my.func,
                                               env = .GlobalEnv)))

Чтобы проверить, я открываю новый сеанс R:

func1 <- function (m, n) {
  charac <- paste ("func2 <- function(x)", m, "*x^", n, sep = "")
  eval(parse(text = charac))
  return(func2)
}
func3 <- function (m, n) {
  my.func <- func1 (m, n)

  do.call("curve",list(expr = substitute(my.func,env = .GlobalEnv)))
}

Чем я звоню

 func3(2,6)
person agstudy    schedule 12.01.2013
comment
@EhsanMasoudi, если это работает, и вы удовлетворены вопросом, вы можете принять его, установив флажок слева. - person agstudy; 12.01.2013
comment
На странице справки для substitute указано, что он оценивается в текущей среде. - person IRTFM; 12.01.2013
comment
Не могли бы вы создать контекст, в котором этот код не выдает ошибку? Я не могу найти функцию 'my.curve - person IRTFM; 12.01.2013
comment
Не с новым кодом, но когда первым аргументом do.call является my.curve, это вызывает ошибку. - person IRTFM; 12.01.2013
comment
@DWin ой... исправлено! Я взломал функцию curve и забыл удалить имя. Спасибо за вашу помощь. - person agstudy; 12.01.2013
comment
Или просто используйте замыкание: func2 <- function(x) x * m ^ n - person hadley; 12.01.2013
comment
substitute ничего не оценивает - person hadley; 12.01.2013

Вы делаете это слишком сложным - вам не нужно делать ничего особенного при создании f2:

f1 <- function (m, n) {
  function(x) m * x ^ n
}
f3 <- function (m, n) {
  f2 <- f1(m, n)
  curve(f2)
}
f3(3, 6)

Это, конечно, можно было бы сделать более кратким, исключив f1:

f4 <- function (m, n) {
  f2 <- function(x) m * x ^ n
  curve(f2)
}
f4(3, 6)

Вы можете найти дополнительную информацию о правилах области видимости R (которые делают эту работу) на https://github.com/hadley/devtools/wiki/Functions

person hadley    schedule 12.01.2013
comment
++ :(скорее для ссылки, чем для ответа) Я думал, что вопрос был в том, как передать аргументы функциям, которые принимают аргументы выражения, используя do.call внутри другой функции, но, возможно, я перечитал его. Читая ваш материал, я задаюсь вопросом, может ли проблема заключаться в том, что передаваемое было закрытием, а не функцией? - person IRTFM; 13.01.2013
comment
@DWin все функции являются замыканиями, так что, вероятно, проблема не в этом. Но я действительно не понимаю, что вы пытаетесь сделать в своем ответе. Вы также можете найти github.com/hadley/devtools/wiki/Computing- на языке полезно, но все еще довольно грубо. github.com/hadley/pryr/blob/master/R/ draw-tree.r также полезен. - person hadley; 13.01.2013
comment
@hadley Да, я усложнил, но это был просто упрощенный пример моего основного кода. как вы знаете, R не имеет возможности обрабатывать символьные вычисления (однако существует пакет под названием Ryacas, и это интерфейс для yacas). В моем коде этот метод применяется для автоматического построения информационной матрицы Фишера для нелинейных моделей без вмешательства пользователя. - person Ehsan Masoudi; 13.01.2013
comment
@EhsanMasoudi R имеет широкие возможности для символьных вычислений. - person hadley; 13.01.2013

Это работает:

func3 <- function (m, n) {
   my.func <- func1 (m, n); print(str(my.func))
   do.call(curve, list(expr=bquote( my.func) ) )
 }
person IRTFM    schedule 12.01.2013
comment
Однако не могу сказать, почему этот метод дает результат. - person Matthew Plourde; 12.01.2013
comment
curve должен принимать функцию, поэтому я не понимаю вашего непонимания. - person IRTFM; 12.01.2013
comment
простите, я не про сюжет, я про тарабарщину, которая выводится на экран. - person Matthew Plourde; 12.01.2013
comment
Извиняюсь. Этот вызов print() был просто моим способом убедиться, что my.func действительно была функцией на тот момент. Его можно смело игнорировать или удалить. - person IRTFM; 13.01.2013

Вам просто нужно удалить строку:

my.func ‹- func1 (m, n)

из функции3.

person user1972522    schedule 12.01.2013
comment
Как это может помочь? - person Matthew Lundberg; 12.01.2013