Есть ли способ заставить комбинацию match.call + eval работать при вызове из функции? - PullRequest
0 голосов
/ 08 апреля 2020

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

pkgFun1 <- function(group) {
  call <- match.call()
  pkgFun2(call)
}

pkgFun2 <- function(call) {
  eval(call$group)
}

Если я просто вызываю pkgFun1(group = 2), он работает нормально. Но я хочу вызвать его из функции:

myFun <- function(x) {
  pkgFun1(group = x)
}
myFun(x = 2)
## Error in eval(call$group) : object 'x' not found

Есть ли способ избежать этой ошибки, если я не могу изменить функции пакета, но только myFun?

Есть похожие вопросы, такие как Проблема с match.call или Нестандартная оценка в пользовательской функции с lapply или с в R , но моя конкретная проблема заключается в том, что я могу не изменять часть кода, содержащую вызов eval.

1 Ответ

0 голосов
/ 08 апреля 2020

Это pkgFun2, что неправильно, поэтому я думаю, что вам не повезло без каких-либо странных искажений. Он должен передать соответствующую среду в eval (); если вы не можете изменить это, то вы не можете это исправить.

Этот хак может показаться работающим, но в реальной жизни это не так:

pkgFun1 <- function(group) {
  call <- match.call()
  f <- pkgFun2
  environment(f) <- parent.frame()
  f(call)
}

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

myFun <- function(x) {
  eval <- function(...) print("Gotcha!")
  pkgFun1(group = x)
}
myFun(x = 2)
# [1] "Gotcha!"

Лучше всего исправить pkgFun2. Вот одно исправление:

pkgFun1 <- function(group) {
  call <- match.call()
  pkgFun2(call, parent.frame())
}

pkgFun2 <- function(call, envir) {
  eval(call$group, envir = envir)
}

Отредактировано, чтобы добавить: На самом деле, есть еще один не очень странный хак, который должен работать с вашими исходными pkgFun1 и pkgFun2. Если вы заставите x выполнить оценку в myFun, чтобы pkgFun1 никогда не увидел выражение x, оно должно работать. Например,

myFun <- function(x) {
  do.call("pkgFun1", list(group = x))
}

Если вы сделаете это, то после myFun(2) переменная pkgFun1 call будет pkgFun1(group = 2), и вы не получите сообщение об ошибке x.

...