在 R 中,如何计算函数内特定环境中的表达式?

In R, how do I evaluate an expression in a specific environment within a function?

在我明显的天真中,我假设当一个人调用 eval 并指定一个环境 (envir) 时,表达式 (expr) 在该环境中被评估。

但是 :-)

这按预期工作:

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

默认情况下,evalparent.frame() 中求值,帮助显示 [t]函数求值的父框架是调用函数的环境.

所以在上面的例子中,这是全局环境,其中确实定义了 xxnn。到目前为止,还不错。

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);

这也符合预期; xxxnnnnewEnv 环境中定义,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);
    }
  }
}

当运行这个时,你得到:

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

所以,那个错误难倒了我。显然,xn 存在于 tempEnvironment 中; tempEnvironment 传递给 eval.

为什么这突然不起作用了?这在函数内部的工作方式不同吗?我是否漏掉了一些明显的东西?

我不确定为什么 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