在 Haskell 中自动插入惰性

Posted

技术标签:

【中文标题】在 Haskell 中自动插入惰性【英文标题】:Automatically inserting laziness in Haskell 【发布时间】:2019-02-20 00:32:25 【问题描述】:

Haskell 模式匹配通常是严格的,例如,f (x:xs) = ... 需要将输入列表评估为 (thunk : thunk)。但有时不需要这样的评估,并且函数可以对某些参数不严格,例如f (x:xs) = 3

理想情况下,在这种情况下,我们可以避免评估参数以获得const 3 的行为,这可以通过无可辩驳的模式来完成:f ~(x:xs) = 3。这为我们带来了性能优势和更大的容错能力。

我的问题是:GHC 是否已经通过某种严格性分析实现了此类转换?如果您也可以指出一些关于它的读物,请不胜感激。

【问题讨论】:

我不确定,但我很确定它不会尝试这样做。无可辩驳的模式存在是有原因的。这个原因是您展示的两个定义之间的语义差异,正如您所描述的那样。 AFAIK 严格性分析旨在减少惰性并尽早执行不可避免的计算,如果可以证明它不会改变语义。但这些只是我的预感和印象。也许仔细阅读the Report 会提供更明确的答案。 如果我们把这个推理发挥到极致,我们也应该将seq x y“优化”为y,这将违背seq的目的。原则上,严格模式可以用作seq 的特例。 ~ 改变了函数的语义,所以 ghc 没有这样做。 【参考方案1】:

据我所知,GHC 永远不会让程序员指定的东西更懒,即使它可以证明这不会改变术语的语义。当我们可以证明语义没有改变时,我认为没有任何根本原因可以避免改变术语的惰性;我怀疑这更像是一种经验观察,即我们不知道在任何情况下这将是一个非常好的主意。 (如果转换改变语义,我会认为 GHC 做出这种改变是一个错误。)

我想到的只有一个可能的例外,即所谓的“完全惰性”转换,很好地描述了on the wiki。总之,GHC会翻译

\a b -> let c = - something that doesn't mention b - in d

\a -> let c = - same thing as before - in \b -> d

避免每次将参数应用于新的b 时重新计算c。但在我看来,这种转变更多的是关于记忆而不是懒惰:在我看来,上述两个术语在懒惰/严格方面具有相同的(指称)语义,只是在操作上有所不同。

【讨论】:

值得注意的是,原始问题中的建议更改确实会改变语义wrt - 它消除了一些可能的底部。有时你想非常精确地控制代码可能导致的底部,而编译器在你身上切换它是很尴尬的。

以上是关于在 Haskell 中自动插入惰性的主要内容,如果未能解决你的问题,请参考以下文章

素数的惰性列表

从惰性IO说起_Haskell笔记6

Haskell代码编程

Haskell 适合量子计算吗?

Haskell“资源缩减”

Haskell严格的字段