R: Promise 找不到对象

R: Promise cannot find object

我知道您可以在 R 中编写一个函数,其中参数的默认值是使用同一函数的另一个参数。

foo <- function(a, b = length(a)) {
  b
}

foo(a = c(1, 2))
[1] 2

但是,一旦我在实际函数调用中使用相同的参数,我就会收到错误消息:

foo(a = c(1, 2), b = length(a))
Error in foo(a = c(1, 2), b = length(a)) : object 'a' not found

我认为 b = length(a) 的承诺应该在函数内部进行评估,其中 a 是已知的,但显然这没有发生。谁能解释一下问题出在哪里以及我该怎么做

foo(a = c(1, 2), b = length(a))

工作?

当键入 foo(a = c(1, 2), b = length(a)) 时,a 必须来自调用环境,而不是函数环境。您需要使用:

x <- 1:2
foo(a = x, b = length(x))

或者使用函数参数:

foo <- function(a, fun = length) { fun(a) }

引用Hadley:

More technically, an unevaluated argument is called a promise, or (less commonly) a thunk. A promise is made up of two parts:

  • The expression which gives rise to the delayed computation. (It can be accessed with substitute(). See non-standard evaluation for more details.)

  • The environment where the expression was created and where it should be evaluated.

你说得对,参数是承诺,只有在需要时才会评估。但是,promise 包括创建它的环境,在本例中是全局环境。

我的理解是,当您显式地为函数提供参数时,默认行为是在给出参数的环境中评估所述参数, 而不是 函数执行环境(如 详情)。

有可能解决这个问题(你是否应该是另一回事)。您可以结合使用 substitute()(捕获未评估的参数)和 eval() 来更改参数评估的环境。这里我们在 foo 中显式评估 b的执行环境:

foo <- function(a, b = length(a)) {
  eval(substitute(b), env = environment())
}

(由于 eval() 中的默认值,只写 eval(substitute(b)) 就足够了。但有时明确一点会很好;像这样,更明显的是我们正在更改评估环境。)

现在以下不会抛出错误:

foo(a = c(1, 2), b = length(a))
#> [1] 2

但是,如果你决定走这条路,你应该非常明确地记录在执行环境中评估 b 参数的函数。例如,当 a 同时出现在给出参数的环境和执行环境中时会发生什么?如果没有详细记录,这可能是意外行为(即使有详细记录,也是难以诊断错误的来源)。

a <- 1:10
foo(a = c(1, 2), b = length(a))
#> [1] 2

有关评估(和陷阱)的更多详细信息,您可以查看the Evaluation chapter in Advanced R

reprex package (v0.2.0) 创建于 2018-07-05。