我正在阅读Hadley Wickhams关于Github的书,特别是this part on lazy evaluation。在那里,他给出了一个懒惰评估结果的例子,在add/adders
函数的部分。让我引用一点:
当使用lapply或循环创建闭包时,[懒惰评估]很重要:
第一次调用其中一个加法器时,add <- function(x) { function(y) x + y } adders <- lapply(1:10, add) adders[[1]](10) adders[[10]](10)
会被懒惰地评估 功能。此时,循环完成并且最终值为 x是10.因此,所有加法器函数都会将10加到它们上面 输入,可能不是你想要的!手动强制进行评估修复 问题:
add <- function(x) { force(x) function(y) x + y } adders2 <- lapply(1:10, add) adders2[[1]](10) adders2[[10]](10)
我似乎并不理解这一点,而且解释很少。有人可以详细说明这个特定的例子,并解释那里发生了什么?我特别对句子感到困惑“此时,循环完成,x的最终值为10”。什么循环?什么最终价值,在哪里?一定是简单的我想念,但我只是没有看到它。非常感谢。
答案 0 :(得分:57)
从R 3.2.0开始,这已经不再适用了!
change log中的相应行显示:
高阶函数,例如apply函数和Reduce() 强制论证它们适用的函数以消除 惰性评估和变量捕获之间的不良交互 在关闭。
确实:
add <- function(x) {
function(y) x + y
}
adders <- lapply(1:10, add)
adders[[1]](10)
# [1] 11
adders[[10]](10)
# [1] 20
答案 1 :(得分:35)
目标:
adders <- lapply(1:10, function(x) add(x) )
是创建一个add
函数列表,第一个添加1到它的输入,第二个添加2,等等。懒惰评估使R等待真正创建加法器函数,直到你真正开始调用函数。问题是在创建第一个加法器函数后,x
循环增加lapply
,结束值为10.当您调用第一个加法器函数时,延迟评估现在构建函数,获取x
的值。问题是原始x
不再等于1,而是等于lapply
循环末尾的值,即10。
因此,延迟评估会导致所有加法器函数等到lapply
循环完成后才真正构建函数。然后他们用相同的值构建他们的函数,即10. Hadley建议的解决方案是强制x
直接评估,避免延迟评估,并使用正确的x
值获取正确的函数。 / p>