关于R中函数参数的困惑

时间:2015-04-24 09:37:07

标签: r function arguments

如果我声明一个函数,我可以参考以前的参数:

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。我不明白的是为什么它在函数声明中起作用,但在我调用时却不行。我不是说它应该或不应该工作,只是想知道范围界定的潜在机制。

2 个答案:

答案 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>

因此,当函数以默认参数值运行时,它将在与函数本身相同的环境中运行。当您显式传递参数时,它会在调用它时在环境中运行(在本例中,它是全局环境)。

这意味着在调用函数时设置其他参数值时,不能将函数参数的名称用作变量。