R:承诺无法找到对象

Gil*_*709 5 r lazy-evaluation

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

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

foo(a = c(1, 2))
[1] 2
Run Code Online (Sandbox Code Playgroud)

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

foo(a = c(1, 2), b = length(a))
Error in foo(a = c(1, 2), b = length(a)) : object 'a' not found
Run Code Online (Sandbox Code Playgroud)

我认为b = length(a)应该在函数内部进行评估,其中a已知,但显然这种情况并未发生.有人可以解释问题所在以及我如何制作

foo(a = c(1, 2), b = length(a))
Run Code Online (Sandbox Code Playgroud)

工作?

Mik*_*ila 3

我的理解是,当您显式向函数提供参数时,默认行为是在给出参数的环境中评估所述参数,而不是函数执行环境(如@Axeman 的答案详细信息)。

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

foo <- function(a, b = length(a)) {
  eval(substitute(b), env = environment())
}
Run Code Online (Sandbox Code Playgroud)

(由于 中的默认值eval(),只需编写 就足够了eval(substitute(b))。但有时明确地表达是件好事;这样,我们正在更改评估环境就更加明显。)

现在以下内容不会引发错误:

foo(a = c(1, 2), b = length(a))
#> [1] 2
Run Code Online (Sandbox Code Playgroud)

然而,如果您决定走这条路,您应该非常明确地记录这样一个函数,即b在执行环境中计算参数。例如,当a参数给出的环境和执行环境中都存在时,会发生什么?如果没有充分记录的话,这可能是意外的行为(并且是难以诊断的错误的来源,即使有充分记录)。

a <- 1:10
foo(a = c(1, 2), b = length(a))
#> [1] 2
Run Code Online (Sandbox Code Playgroud)

有关评估(和陷阱)的更多详细信息,您可以查看Advanced R 中的评估章节

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