当前位置: 首页 > 知识库问答 >
问题:

解释懒惰的评估怪癖

别兴国
2023-03-14

我正在阅读HadleyWickhams关于Github的书,特别是关于懒惰评估的这一部分。在那里,他给出了一个懒惰求值结果的例子,在函数的添加部分。让我引用这一点:

这个[惰性评估]在使用lApplication或循环创建闭包时很重要:

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

x在您第一次调用其中一个加法器函数时被延迟计算。此时,循环完成,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”。什么循环?最终值是多少,在哪里?一定是我错过了一些简单的东西,但我就是看不到。提前非常感谢。

共有2个答案

相诚
2023-03-14

目标是:

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

是创建一个添加函数的列表,第一个向其输入中添加1,第二个添加2,等等。延迟求值会导致R等待真正创建加法器函数,直到您真正开始调用函数。问题是,在创建第一个加法器函数后,x会增加lappy循环,最终值为10。当您调用第一个加法器函数时,惰性求值现在构建该函数,得到x的值。问题是原来的x不再等于1,而是等于lappy循环末尾的值,即10。

因此,延迟求值会导致所有加法器函数等到lappy循环真正构建函数完成后再执行。然后,它们用相同的值构建函数,即10。哈德利建议的解决方案是强制直接计算x,避免懒惰的计算,并使用正确的x值获得正确的函数。

李谦
2023-03-14

从R 3.2.0开始,这不再是事实!

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

应用函数和Reduce()等高阶函数现在强制参数到它们应用的函数,以消除闭包中延迟计算和变量捕获之间的不良交互。

事实上:

add <- function(x) {
  function(y) x + y
}
adders <- lapply(1:10, add)
adders[[1]](10)
# [1] 11
adders[[10]](10)
# [1] 20
 类似资料:
  • 问题内容: 我最近读到了Python 3的一个好处是它很懒。那就更好了 而不是 我很好奇的是如何使用这种懒惰。如果生成映射对象,例如,如何访问生成的操作/列表中的特定元素。在我所见过的几乎所有文档中,他们都会做类似或的事情(据我所知),它放弃了惰性概念,因为它隐式将地图转换为列表。 我想我正在寻找的是能够以与我可以懒惰地懒惰地生成地图对象类似的方式使用地图对象的能力,并且可以在没有巨大计算量的情况

  • 我已经写了两个版本的nqueens问题,我认为它们应该有相似的效率,但事实并非如此。我认为这是由于哈斯克尔的懒惰评估行为。有人能解释一下下面的例子是如何工作的吗, 您可以通过调用nqueens1 8 8或nqueens2 8 8对其进行评估,以对大小为8的板进行评估。 虽然nqueens2工作效率很高,但nqueens1存在性能问题。我相信这是因为递归调用(nqueens n(k-1))被多次评估

  • 问题内容: 例如,如果我有以下语句: 如果foo1为true,python将检查foo2的条件吗? 问题答案: 是的,Python懒惰地评估布尔条件。 该文件说, 表达式x和y首先计算x;如果x为假,则返回其值;否则,将评估y并返回结果值。 表达式x或y首先计算x; 如果x为true,则返回其值;否则,将评估y并返回结果值。

  • 问题内容: 我在python应用程序中使用标准的python日志记录模块: 问题是,尽管未启用调试级别,但在每次循环迭代时都会评估该愚蠢的日志消息,这会严重损害性能。 有什么解决办法吗? 在C ++中,我们提供了提供以下宏的软件包: 有效评估为 但是,由于Python(AFAIK)中没有宏,是否有一种有效的日志记录方法? 问题答案: 日志记录模块已经对您要执行的操作提供了部分支持。做这个: …代替

  • 问题内容: 什么是Python中的惰性评估? 一个网站说: 在Python 3.x中,该函数返回一个特殊的范围对象,该对象按需计算列表元素(延迟或延迟评估): 这是什么意思? 问题答案: 由(或在Python2.x中)返回的对象被称为惰性迭代。 生成器没有将整个范围存储在内存中,而是存储的定义并仅在需要时才计算下一个值(又称惰性求值)。 本质上,生成器允许您返回类似于结构的列表,但是这里有一些区别

  • 问题内容: 抱歉,这听起来像是一个很愚蠢的问题。 但是我在网上搜索了Google,还专门搜索了php.net网站和stackoverflow.com网站。 我知道PHP 在使用运算符时会进行 短路惰性评估 ,但是在PHP手册中它在何处清晰明了? 我发现只有Wikipedia作为唯一的“可信赖”资源,它说PHP对这些运算符进行了惰性评估。 问题答案: 我可以找到关于PHP的短路实现的“官方”最接近的