В R, как я могу оценить выражение в определенной среде внутри функции? - PullRequest
3 голосов
/ 08 мая 2019

В своей очевидной наивности я предположил, что когда кто-то вызывает eval и указывает среду (envir), выражение (expr) оценивается в этой среде.

Однако :-)

Это работает, как и ожидалось:

xx <- 10
nn <- 20
exprs <- binom.test(x=xx,n=nn)
eval(exprs);

По умолчанию eval вычисляет в parent.frame(), что показывает справка: [t] родительский кадр оценки функцииэто среда, в которой была вызвана функция.

Итак, в приведенном выше примере это глобальная среда, в которой действительно определены xx и nn.Пока все хорошо.

newEnv <- new.env();
assign('xxx', 10, envir = newEnv);
assign('nnn', 30, envir = newEnv);
exprs2 <- expression(binom.test(x=xxx,n=nnn));
eval(exprs2, envir=newEnv);

Это также работает, как и ожидалось;xxx и nnn определены в среде newEnv, и binom.test оценивается в этой среде.

Теперь мы заключаем это в функцию (ту, которую я пытаюсь построить - яя собираю его с помощью пакета pwr, но для этого примера я использую binom.test, потому что это база R и он все еще не работает: -)

loopFunction <- function(expr,
                         ...) {

  ### Get all 'dots' in a named list
  arguments <- list(...);
  argNames <- names(arguments);

  if (any(length(tail(arguments, -2) > 1))) {
    stop("Only the first two arguments may have length > 1!");
  }

  for (esIndex in seq_along(arguments[[1]])) {
    for (pwrIndex in seq_along(arguments[[2]])) {
      tempEnvironment <-
        new.env();
      assign(argNames[1], arguments[[1]][esIndex],
             envir = tempEnvironment);
      assign(argNames[2], arguments[[2]][pwrIndex],
             envir = tempEnvironment);
      if (length(arguments) > 2) {
        for (i in 3:length(arguments)) {
          assign(argNames[i], arguments[[i]],
                 envir = tempEnvironment);
        }
      }
      print(argNames);
      print(as.list(tempEnvironment));
      print(ls(tempEnvironment));
      print(get('x', envir=tempEnvironment));
      print(get('n', envir=tempEnvironment));
      return(eval(expr = expression(expr),
                  envir = tempEnvironment)$estimate);
    }
  }
}

При запуске этого выget:

loopFunction(binom.test(x=x,n=n), x=c(10,20), n=c(30, 100));

#> [1] "x" "n"
#> $x
#> [1] 10
#> 
#> $n
#> [1] 30
#> 
#> [1] "n" "x"
#> [1] 10
#> [1] 30
#> Error in binom.test(x = x, n = n): object 'x' not found

Итак, эта ошибка ставит меня в тупик.ясно, что x и n существуют в tempEnvironmenttempEnvironment передается eval.

Почему это внезапно перестает работать?Это работает по-другому внутри функций?Я что-то упускаю из виду?

1 Ответ

2 голосов
/ 10 мая 2019

Я не уверен, почему expression() не работает в этом контексте.Однако это работает, если вы пишете expr в виде строки и заменяете expression(expr) на parse(text=expr):

loopFunction <- function(expr,
                         ...) {

  ### Get all 'dots' in a named list
  arguments <- list(...);
  argNames <- names(arguments);

  if (any(length(tail(arguments, -2) > 1))) {
    stop("Only the first two arguments may have length > 1!");
  }

  for (esIndex in seq_along(arguments[[1]])) {
    for (pwrIndex in seq_along(arguments[[2]])) {
      tempEnvironment <-
        new.env();
      assign(argNames[1], arguments[[1]][esIndex],
             envir = tempEnvironment);
      assign(argNames[2], arguments[[2]][pwrIndex],
             envir = tempEnvironment);
      if (length(arguments) > 2) {
        for (i in 3:length(arguments)) {
          assign(argNames[i], arguments[[i]],
                 envir = tempEnvironment);
        }
      }
      print(argNames);
      print(as.list(tempEnvironment));
      print(ls(tempEnvironment));
      print(get('x', envir=tempEnvironment));
      print(get('n', envir=tempEnvironment));
      return(eval(expr=parse(text=expr), envir =tempEnvironment)$estimate)
    }
  }
}

loopFunction("binom.test(x, n)", x=10, n=30)

Результат:

> loopFunction("binom.test(x, n)", x=10, n=30)
[1] "x" "n"
$`x`
[1] 10

$n
[1] 30

[1] "n" "x"
[1] 10
[1] 30
probability of success 
             0.3333333 
...