Haskell 严格评估的巧妙运用在哪里?

Haskell 严格评估的巧妙运用在哪里?,haskell,lazy-evaluation,Haskell,Lazy Evaluation,似乎有很多例子表明,在一种惰性评估的语言中,聪明的事情是无法在严格评估的环境中完成的。例如,Haskell或中的无限列表 有没有用严格评估过的语言做的聪明的事情,用懒散评估过的语言做不到的例子?好吧,没有,根据定义或多或少。在惰性评估语言中,从定义上讲,您应该获得与“活力”(人们现在真的在使用“严格”评估吗?)评估相同的结果,除了评估延迟到需要时、存储影响等等。因此,如果您可以得到除此之外的其他行为,那将是一个bug。在严格的求值语言(如C)中,可以通过将thunk返回到值(Func)而不是值本

似乎有很多例子表明,在一种惰性评估的语言中,聪明的事情是无法在严格评估的环境中完成的。例如,Haskell或中的无限列表


有没有用严格评估过的语言做的聪明的事情,用懒散评估过的语言做不到的例子?

好吧,没有,根据定义或多或少。在惰性评估语言中,从定义上讲,您应该获得与“活力”(人们现在真的在使用“严格”评估吗?)评估相同的结果,除了评估延迟到需要时、存储影响等等。因此,如果您可以得到除此之外的其他行为,那将是一个bug。

在严格的求值语言(如C)中,可以通过将thunk返回到值(Func)而不是值本身来实现延迟求值。作为c#中Y组合子构造的一个示例,可以通过以下方式完成:

public Func<int, int> Y(Func<Func<int, int>, Func<int, int>> f)
{
    return x => f(Y(f))(x);
}
同样,严格程序和惰性程序的结果应该是等价的。差异在于时间和空间限制和/或语言表达能力。除了惰性对不需要的值的性能影响之外,在惰性语言中,人们可以轻松地引入新的语言结构,而无需额外的语言概念(例如LISP中的宏)。不管怎样,懒惰会咬到你
同样的想法可能比严格的语言更复杂。(难道haskell编译器不应该认识到compute
+1
比make thunk
(x+1)
?)便宜吗?

我用Erlang编程了一点,并发现我在大学时学到的懒惰评估的缺乏相当令人沮丧

我已经简要地介绍了一些project Euler问题,特别是那些处理素数的问题

使用惰性求值,您可以有一个返回所有素数列表的函数,但它实际上只返回您实际需要的素数。因此,很容易说“给我前n个素数”


如果没有惰性评估,您往往会得到一个更具约束性的“给我一个1到n之间所有素数的列表”。

否;有些事情你可以通过惰性计算(也称为正常顺序缩减,或最外层缩减)来做,但严格计算是做不到的,反之亦然

这是因为惰性评估在某种程度上是“最通用”的评估方式,称为:

计算充分性定理: 如果某个求值顺序终止并生成特定结果,则惰性求值也将终止并生成相同的结果


*(请注意,我们这里并不是在讨论图灵等价)

您可以用渴望(严格)的语言而不是懒惰的语言轻松完成的主要事情:

  • 从源代码中预测程序的时间和空间成本

  • 允许副作用,包括可变数组的恒定时间更新,这使得快速实现某些算法更容易

在我看来,一种渴望的语言的主要好处是,让您的代码以您想要的方式执行要容易得多,而且很少有性能陷阱,在这些陷阱中,代码中的一个小变化会导致性能上的巨大变化


话虽如此,总的来说我更喜欢用Haskell写复杂的东西。

不幸的是,被评为最佳答案的答案存在逻辑错误。 根据Porges引用的定理,并不意味着一个人可以用懒惰的语言做更多的事情


相反的证据是,所有惰性语言中的程序都被编译成严格语言中的等价物(进一步编译为汇编程序),或者由严格语言编写的解释器执行(是的,解释器最终是汇编程序)在日常语言中,懒惰最明显的用法是“if”语句,其中只执行条件语句的一个分支

与纯非严格(懒惰)语言相反的是纯严格语言

至少有一种情况下,“纯粹严格”是有益的,即

链接文章的粗略解释:

很久以前,在CPU世界中,在测试分支条件时加载要执行的指令。在某些情况下,添加了指令管道以缩短加载时间。缺点是CPU不知道需要加载哪个分支,因此默认情况下会加载一个分支。如果分支转到另一个方向,则在加载另一个分支的代码时,管道将暂停

解决方案是加载两个分支,执行两个分支,然后条件的结果告诉您保留哪个分支结果,以及丢弃哪个分支结果。那你就不会有管道阻塞了


这是我最喜欢的(仅?)纯严格语言好处的例子。

我想到了“Hello,World”程序,或者所有基本上与副作用有关的东西

在严格的计算中,计算表达式很容易产生副作用,因为您可以清楚地了解计算顺序,从而了解副作用的顺序,这在副作用中通常很重要。这是严格评估的基本优势,也是大多数语言都有严格评估的原因。以及为什么即使像C这样的面向性能的语言也经常使用传递值模型


两者都可以做同样的事情,只是人类的困难程度不同,你可以用严格的语言很好地模拟无限列表,你也可以用非严格的语言模拟所有副作用的影响。

实际上,懒惰与严格有着略微不同的语义。例如,在严格的语言中,“const 1 undefined”是未定义的,但在惰性语言中它的计算结果是1。原因是严格的语言评估“未定义”,而懒惰的语言评估“未定义”。尽管被评为最佳答案,但您的陈述是错误的,请参见下面我的答案。这
Y f = f (Y f)