R:承诺找不到对象

时间:2018-07-05 07:37:30

标签: r lazy-evaluation

我知道您可以在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))

工作吗?

2 个答案:

答案 0 :(得分:4)

键入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

  

从技术上讲,未经评估的论点称为承诺,或者   (较不常见)重击。许诺由两部分组成:

     
      
  • 引起延迟计算的表达式。 (可以使用替代方法()进行访问。有关非标准评估,请参见   更多细节。)

  •   
  • 在其中创建表达式以及应该对其进行评估的环境。

  •   

您很正确地认为参数是承诺,并且直到需要时才进行评估。但是,承诺包括创建它的环境,在这种情况下是在全球环境中。

答案 1 :(得分:3)

我的理解是,当您为函数显式提供参数时,默认行为是在函数执行环境中(而不是@Axeman's answer详细说明)在给定参数的环境中评估所述参数。 )。

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

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创建。