如果我声明一个函数,我可以参考以前的参数:
blah <- function( a=1, b=a ) { print(sprintf("a=%d, b=%d", a, b)) }
输出结果为:
> blah(10)
[1] "a=10, b=10"
> blah(10, b=30)
[1] "a=10, b=30"
但是,以下情况不起作用:
> blah(a=10, b=a)
Error in sprintf("a=%d, b=%d", a, b) : object 'a' not found
实际上,这或多或少是人们所期望的;那么为什么声明blah <- function(a=10, b=a)
有效呢?为什么范围与我调用函数时不同?
另外,为什么只有在调用sprintf
时才会出现错误?调用函数时为什么不立即抛出错误?我很迷惑。
修改
这里解释我的困惑。当我声明一个函数时,不评估参数。 R具有惰性评估,并在需要时评估变量。考虑一下:
> blah <- function( a=1, b=print("foo") ) { print( "So far, so good") ; print( b ) }
>
没有评价。我现在打电话给你:
> blah()
[1] "So far, so good"
[1] "foo"
[1] "foo"
评估函数中的第一个语句,然后 print("foo")
。然而,那个时代,我们在功能范围内拥有它。那么为什么b=a
不被评估呢?我们已经在函数发生时已经声明了。
编辑2:
在你得出错误的结论之前,请注意,由于R的惰性求值,在R中的函数声明中引用前一个参数是perfectly fine。我不明白的是为什么它在函数声明中起作用,但在我调用时却不行。我不是说它应该或不应该工作,只是想知道范围界定的潜在机制。
答案 0 :(得分:2)
当你这样做时:
> blah(a=10, b=a)
您说:我的全球环境中有值10
,我将其分配给参数a
。我的全局环境中有变量 a
,我将其值分配给参数b
。
变量a
与函数的参数a
完全不同!如果未定义变量a
,并且您想将其提供给函数,则R
会大喊。
您将完成相同的错误:
> blah(a=10, b=nonExistingVariable)
Error in sprintf("a=%d, b=%d", a, b) : object 'NonExistingVariable' not found
答案 1 :(得分:2)
评估两个表达式的位置有所不同。调用函数时,将在当前范围内评估参数。定义函数时,将在函数范围内计算参数。这通常是你想要的行为。
因此,当您调用该函数时,您可以控制传递给该函数的所有值。您不必知道函数内部使用的变量。通过懒惰的评估,这种结构也有效:
blah <- function( a=1, b=x ) {
x < a+10
print(sprintf("a=%d, b=%d", a, b))
}
blah(1)
所以试着打电话
blah(1, b=x+5)
更没意义,因为从技术上讲,你甚至不应该知道函数内部存在x
变量。
您可以通过此示例查看环境的差异。在这里,我们使用parent.frame()
来获取调用函数的环境。
myenv <- function() parent.frame()
foo <- function( a=myenv() ) {
print(environment())
print(a)
}
foo()
# <environment: 0x10c8b1948>
# <environment: 0x10c8b1948>
foo( a=myenv() )
# <environment: 0x10bd85ad8>
# <environment: R_GlobalEnv>
因此,当函数以默认参数值运行时,它将在与函数本身相同的环境中运行。当您显式传递参数时,它会在调用它时在环境中运行(在本例中,它是全局环境)。
这意味着在调用函数时设置其他参数值时,不能将函数参数的名称用作变量。