为什么 R 无法通过词法作用域找到参数的值?

Ano*_*n R 4 arguments r function lexical-scope

我一直在阅读 Hadley Wickham 的《Advanced R》,以便更好地了解 R 的机制及其幕后工作原理。到目前为止,我很享受它,一切都很清楚。有一个问题一直困扰着我,但我还没有找到解释。我非常熟悉 R 的作用域规则,它决定如何将值分配给自由变量。然而,我一直在努力解决为什么 R 在第一种情况下无法通过词法作用域找到形式参数的值的问题。考虑以下示例:

y <- 4
f1 <- function(x = 2, y) {
  x*2 + y
}

f1(x = 3)
Run Code Online (Sandbox Code Playgroud)

它通常会抛出错误,因为我没有为 argument 分配默认值y。然而,如果我y在函数体中创建一个局部变量,它不会抛出任何错误:我还在 Matloff 教授的书中读到,参数的行为就像局部变量,所以这就是为什么这个问题对我来说仍然是个谜。

f1 <- function(x = 2, y) {
  y <- 4
  x*2 + y
}

f1(x = 3)
Run Code Online (Sandbox Code Playgroud)

这里也没有错误,原因也很清楚:

y <- 2
f2 <- function(x = 2) {
  x*2 + y
}

f2()
Run Code Online (Sandbox Code Playgroud)

预先非常感谢您。

MrF*_*ick 5

请注意,R 仅在您使用该变量时才会抛出错误。如果你有

f1 <- function(x = 2, y) {
  x*2 + 5
}

f1(x = 3)
# [1] 11
Run Code Online (Sandbox Code Playgroud)

一切都会好起来的。这是因为该参数是一个“承诺”,只有在您实际使用它时才会得到解决。这允许你做类似的事情

f1 <- function(x = 2, y=x+5) {
  x*2 + y
}

f1(x = 3)
# [1] 14
Run Code Online (Sandbox Code Playgroud)

其中值实际上将使用在评估 Promise 时传递给函数y的值。x此外你还可以做

f1 <- function(x = 2, y=z+2) {
  z <- x + 10
  x*2 + y
}

f1(x = 3)
[1] 21
Run Code Online (Sandbox Code Playgroud)

wherey能够获取z调用函数时甚至不存在的值。同样,这是因为参数值是承诺,并且仅在实际使用时才进行评估。他们在评估时可以访问环境中的所有值。但请注意,这仅有效,因为默认参数值是在函数体的上下文中计算的。这与将值传递给函数时不同。在这种情况下,该值在调用环境中计算,而不是在本地函数体中。所以你不能这样做

f1(x = 3, y=z+2)
# Error in f1(x = 3, y = z + 2) : object 'z' not found
Run Code Online (Sandbox Code Playgroud)

您在第一个函数中收到错误的原因是,y当您尝试在 中使用它时, 的值不存在x*2 + y。由于您已定义y为参数,因此它不再是“自由”变量,并且不会在父作用域中查找。您在第二个函数中不会收到错误,因为您已将变量重新绑定y到本地函数变量,因此您根本不会使用参数值。

如果你跑了

f1 <- function(x = 2, y) {
  y <- 4
  x*2 + y
}

f1(x = 3, y=200)
# [1] 10
Run Code Online (Sandbox Code Playgroud)

2000年基本上就消失了。重新分配后,您将无法再访问该值y。R 在重新定义之前不会检查变量是否已经存在,因此没有任何东西会尝试评估y函数参数的承诺值。

一旦承诺被评估,参数将像局部变量一样起作用。