解释一个懒惰的评价怪癖

Max*_*m.K 60 r lazy-evaluation

我正在阅读Hadley Wickhams关于Github的书,特别是关于懒惰评估的这一部分.在那里,他举例说明了懒惰评估的后果,在有add/adders功能的部分.让我引用一下:

在使用lapply或循环创建闭包时,[懒惰评估]很重要:

add <- function(x) {
  function(y) x + y
}
adders <- lapply(1:10, add)
adders[[1]](10)
adders[[10]](10)
Run Code Online (Sandbox Code Playgroud)

在第一次调用其中一个加法器函数时,会对x进行延迟计算.此时,循环完成,x的最终值为10.因此,所有加法器函数都会在其输入上添加10,可能不是您想要的!手动强制评估修复了问题:

add <- function(x) {
  force(x)
  function(y) x + y
}
adders2 <- lapply(1:10, add)
adders2[[1]](10)
adders2[[10]](10)
Run Code Online (Sandbox Code Playgroud)

我似乎不明白那一点,而且那里的解释很少.有人可以详细说明这个特定的例子,并解释那里发生了什么?我特别对句子感到困惑"此时,循环完成,x的最终值为10".什么循环?什么最终价值,在哪里?一定是简单的我想念,但我只是没有看到它.非常感谢提前.

jhi*_*hin 57

从R 3.2.0开始,这已不再适用!

更改日志中的相应行显示:

诸如apply函数和Reduce()之类的高阶函数现在强制它们应用的函数的参数,以便消除惰性求值和闭包中的变量捕获之间的不期望的交互.

事实上:

add <- function(x) {
  function(y) x + y
}
adders <- lapply(1:10, add)
adders[[1]](10)
# [1] 11
adders[[10]](10)
# [1] 20
Run Code Online (Sandbox Code Playgroud)


Pau*_*tra 35

目标:

adders <- lapply(1:10, function(x)  add(x) )
Run Code Online (Sandbox Code Playgroud)

是创建一个add函数列表,第一个添加1到它的输入,第二个添加2,等等.懒惰的评估使R等待真正创建加法器函数,直到你真正开始调用函数.问题是在创建第一个加法器函数之后,循环x增加lapply,结束于值10.当你调用第一个加法器函数时,延迟评估现在构建函数,得到值x.问题是原始x不再等于1,而是等于lapply循环结束时的值,即10.

因此,延迟评估会导致所有加法器函数等到lapply循环完成后才真正构建函数.然后他们用相同的值构建他们的函数,即10. Hadley建议的解决方案是强制x直接评估,避免惰性求值,并使用正确的x值获得正确的函数.

  • 好吧,让我重新说一下,看看我是否做对了.当我们调用`lapply`时,R会记住所有10个加法器函数的结构,但还没有评估x.当我们调用第一个加法器函数时,R说,aha,让我们看看是什么,取x,在lapply调用的那一点已经是10,并将第一个被调用的加法函数计算为10 + y.对于剩余的加法器函数,它们都是相同的.可能粗略地说,但这是逻辑吗? (4认同)