我知道您可以在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))
工作吗?
答案 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创建。