R中列表中嵌入的闭包是否存在错误



这里有一个闭包的简单例子,它是一个返回带有嵌入数据的函数的函数(http://adv-r.had.co.nz/Functional-programming.html#closures):

fFactory <- function(letter) {
function(Param) {
paste("Enclosed variable:", letter, "/ function parameter:", Param)
}
}

创建函数时,返回函数中使用letter

> FUN <- fFactory("a")
> FUN("toto")
[1] "Enclosed variable: a / function parameter: toto"

它之所以有效,是因为变量letter嵌入了函数的环境中:

as.list(environment(FUN))
$letter
[1] "a"

如果现在我们在这样的列表中创建函数:

l <- list()
for(letter in letters) {
l[[letter]]$FUN <- fFactory(letter)    
}

正常情况下,运行项目";a";必须返回与以前相同的结果,但事实并非如此:

> l[["a"]]$FUN("toto")
[1] "Enclosed variable: z / function parameter: toto"

显然,因为嵌入函数中的环境不是我们所期望的:

> as.list(environment(l[["a"]]$FUN))
$letter
[1] "z"

它为列表中的所有闭包返回在列表最后一项中创建的最后一个闭包。

我想我这样做并没有误用R语言,而且该语言中存在漏洞。你们中有谁能证实这一点,或者向我解释我的错误在哪里?

强制使用force()对参数letter求值。

fFactory2 <- function(letter) {
force(letter)
function(Param) {
paste("Enclosed variable:", letter, "/ function parameter:", Param)
}
}
l2 <- list()
for(letter in letters) {
l2[[letter]]$FUN <- fFactory2(letter)    
}
l2[["a"]]$FUN("toto")
l2[["b"]]$FUN("toto")
l2[["w"]]$FUN("toto")

以下是一个解释(在@user2554330回答之后):

在R中,函数的参数在首次使用之前不会求值。因此,列表中所有函数的参数都是全局变量字母,当您创建它们时,您会在循环中更改它,但在调用它们之前,您永远不会进行求值。因此,函数在第一次调用时首先评估letter,然后得到奇怪的结果。

这是您的错误@鲁伊·巴拉达斯给你解决办法。这里有一个解释:

在R中,函数的自变量在第一次使用之前不会进行求值。因此,列表中所有函数的参数都是全局变量letter,您可以在创建它们时在循环中更改它,但在调用它们之前,您永远不会进行求值。因此,函数在第一次调用时首先评估letter,然后得到奇怪的结果。

您可以按照Rui所说的方法来解决这个问题:在创建函数之前,强制对参数进行求值。

最新更新