解释一个懒惰的评价怪癖

我正在阅读哈德利·威克汉姆(Hadley Wickhams)的关于Github的书,特别是关于懒惰评价的这一部分 。 在那里他给出了懒惰评估的后果的例子,在add/adders函数的部分。 让我引用这一点:

用lapply或循环创build闭包时,这个[懒惰的评估]是很重要的:

 add <- function(x) { function(y) x + y } adders <- lapply(1:10, add) adders[[1]](10) adders[[10]](10) 

当你第一次调用其中一个加法器函数时,x是懒惰的评估。 此时,循环完成,x的最终值为10.因此,所有的加法器函数都会将10加到它们的input上,可能不是你想要的! 手动强制评估可以解决问题:

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

我似乎没有明白这一点,而且那里的解释很less。 有人可以详细说明这个特定的例子,并解释发生了什么? 我特别困惑的句子“在这一点上,循环完成,x的最终值是10”。 什么循环? 什么终极价值在哪里? 一定是简单的东西我想念,但我只是没有看到它。 非常感谢。

目标是:

 adders <- lapply(1:10, function(x) add(x) ) 

是创build一个add函数的列表,第一个添加1到它的input,第二个添加2等。懒惰的评估导致R等待真正创build加法器函数,直到你真的开始调用函数。 问题是在创build第一个加法器函数后, xlapply循环增加,结束于10的值。当你调用第一个加法器函数时,lazy evaluation现在生成函数,得到x的值。 问题是,原来的x不再等于1,而是等于lapply循环结尾的值,即10。

因此,懒惰的评估会导致所有的加法器函数等待lapply循环完成后才真正构build函数。 然后他们用相同的值build立它们的函数,即10。哈德利提出的解决scheme是迫使x直接被评估,避免懒惰的评估,并用正确的x值得到正确的函数。

从R 3.2.0开始,这不再是真的!

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

诸如apply函数和Reduce()之类的高阶函数现在强加参数给它们所应用的函数,以消除懒惰评估和闭包中的variables捕获之间的不期望的交互作用。

事实上:

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