简体   繁体   English

haskell 在处理复杂的程序流程时有多懒惰

[英]how lazy is haskell when dealing with complicated program flow

I was wondering how smart/lazy Haskell is.我想知道 Haskell 有多聪明/懒惰。 Can I always be sure that Haskell will only do what is necessary to generate a certain output?我能否始终确定 Haskell 只会执行生成某个 output 所需的操作?

No.不。

Haskell specifies a denotational semantics for its core lambda-like calculus, and you can rely on that semantics. Haskell 为其核心类 lambda 演算指定了指称语义,您可以依赖该语义。 Additionally, there is a metatheory proof that a particular reduction order -- known colloquially as "lazy evaluation" -- realizes that semantics;此外,还有一个元理论证明,一个特定的归约顺序——俗称“惰性求值”——实现了这种语义; and so many people use that as their mental model of how Haskell programs behave.很多人将其用作 Haskell 程序行为方式的心理 model。

There are two broad categories of ways that a Haskell program may end up evaluating more than necessary: Haskell 程序可能最终评估超出必要的两种方式:

  • The Haskell implementation may choose to evaluate more. Haskell 实现可以选择评估更多。 GHC uses lazy evaluation in most places, but I believe it will use other evaluation orders for efficiency in some cases. GHC 在大部分地方都使用惰性求值,但我相信在某些情况下它会使用其他求值顺序来提高效率。 You could also look at the Eager Haskell project, which is attempting to use another implementation strategy;您还可以查看Eager Haskell项目,它正在尝试使用另一种实现策略; or, in principle, an implementation would be within its rights to choose to speculatively fork some computations to another thread (and then throw away the results if they weren't needed).或者,原则上,实现将有权选择推测性地将某些计算分叉到另一个线程(然后在不需要时丢弃结果)。

  • The denotational semantics specified may demand more evaluation than "necessary".指定的指称语义可能需要比“必要”更多的评估。 For example, one that occasionally trips up beginners:例如,偶尔会绊倒初学者的一个:

     primes:: [Int] primes = 2: filter prime [3,5..] prime:: Int -> Bool prime x = and [x `mod` p /= 0 | p <- primes, p < x]

    When checking whether 3 should be in the list primes , it is in fact not necessary to check any of the elements of primes past 2 , because the sequence is strictly monotonically increasing.在检查3是否应该在列表primes中时,实际上没有必要检查超过2primes的任何元素,因为该序列是严格单调递增的。 But Haskell is not (does not try to be) smart enough to notice that;但是 Haskell 不够聪明(不尝试)来注意到这一点; it will go straight on trying to check the rest of the primes and end up in an infinite loop instead of giving the list of primes.它将 go 直接尝试检查primes的 rest 并最终进入无限循环,而不是给出素数列表。

    An even smaller example: you could think that x && False is always False , but x will typically be evaluated anyway, because the semantics says this should be an infinite loop if x is.一个更小的例子:你可以认为x && False总是False ,但x通常会被评估,因为语义表明如果x是,这应该是一个无限循环。 (Contrast False && x , which typically does not result in evaluating x .) (对比False && x ,这通常不会导致评估x 。)

That said, when you say "complex structure", one thing that comes to mind is: does Haskell do the laziness thing even with custom data types that I define ?也就是说,当您说“复杂结构”时,想到的一件事是:即使使用我定义的自定义数据类型, Haskell 也会做懒惰的事情吗? That is, do complex structures like hash maps and balanced trees and kd trees and so forth get treated lazily?也就是说,像 hash 映射和平衡树和 kd 树等复杂结构会被延迟处理吗? The answer there is yes ;答案是肯定的; there is nothing fundamentally special about any of the types in the Prelude except IO .除了IO之外, Prelude中的任何类型都没有什么特别之处。 Lists, booleans, Maybe s, and so forth are lazy not because the compiler knows special things about them, but simply as a consequence of the reduction rules specified by Haskell and their declarations as types.列表、布尔值、 Maybe等是惰性的,不是因为编译器知道关于它们的特殊信息,而是因为 Haskell 指定的缩减规则及其作为类型的声明。

Of course, there are ways to opt-out of laziness.当然,有一些方法可以选择退出懒惰。 Some of the structures you will see on Hackage do that in various ways;您将在 Hackage 上看到的一些结构以各种方式做到这一点; but don't worry, usually this will be declared in their documentation.但别担心,通常这会在他们的文档中声明。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM