是否有使用严格评估的 Haskell 编译器或预处理器?

Posted

技术标签:

【中文标题】是否有使用严格评估的 Haskell 编译器或预处理器?【英文标题】:Is there a Haskell compiler or preprocessor that uses strict evaluation? 【发布时间】:2010-11-03 00:31:13 【问题描述】:

我正在寻找默认情况下使用严格评估而不是惰性评估的 Haskell 编译器。我只会使用 OCaml,但 Haskell 的语法比 OCaml 的好多了(而且 Haskell 是纯粹的,并且有很酷的特性,例如类型类)。

我真的不想在我的程序中不断地使用!s 和$!s。带有开关或预处理器以放入严格性注释的编译器会非常好。如果在某些地方也有一种使用惰性求值的方法也会很有帮助,以防万一我想要一个无限列表之类的东西(我可能永远不会)。

请不要试图说服我懒惰的评估更好,我真的需要性能。 IIRC,Simon Peyton Jones 甚至说惰性评估并不是真正必要的,它主要是为了防止他们使语言变得不纯。

【问题讨论】:

如果存在这样的预处理器(我不知道),这可能意味着您必须重新编译您使用的每个库,因为它们都是惰性的(并且被编写为在懒惰的环境)。如果突然使用严格的评估,我猜大多数 Haskell 库都会崩溃。 @Tom Lokhorst:当然有些东西会坏掉,但我希望大多数东西在未经修改的情况下都能正常工作。 你有一个例子说明惰性求值导致性能很差吗? 我当然愿意。与我的机器中只有 6 GB 的内存和空间泄漏有关。如果您愿意签署 NDA,我会非常乐意在下次发生时让您帮助我。 我怀疑我能否提供帮助,无论是否保密。我希望从你的例子中学到一些东西,但是一个完全存在的陈述并不是很有启发性。 :-) 【参考方案1】:

我真的不想在我的程序中不断地放 !s 和 $!s

你做错了,如果你是这样编程 Haskell 的:) 你根本不需要这样做。使用 GHC,使用 -O2,在适当的时候使用严格的数据类型,在适当的时候使用惰性数据类型。不要认为懒惰会成为一个问题——它可以解决很多问题。

【讨论】:

【参考方案2】:

如果你有一个使用严格评估的 Haskell 编译器,它不会编译 Haskell。 懒惰 非严格性是 Haskell 规范的一部分!

但是,还有其他选择。

DDC 试图创建一个明确的 Haskell 惰性变体,它支持破坏性更新,同时保留 Haskell 的所有其他优点。有一个问题:编译器目前只处于α阶段,虽然它看起来至少是可用的。

Create a preprocessor, as others have done.

学习“以正确的方式”使用 Haskell。如果您可以将测试用例简化为可公开展示的内容,您可以将其发布在 Haskell-Café mailing list 上,人们对这类有关非严格性影响的问题非常有帮助。

李>

【讨论】:

DDC 看起来很不错。现在我必须掌握效果系统而不是单子...... 准确地说,非严格性是 Haskell 规范的一部分,而不是懒惰。懒惰只是 GHC 选择的评估顺序。【参考方案3】:

过去曾有过两次严格评估 Haskell 的尝试:

Jan-Willem Maessen 的Eager Haskell Rob Ennals博士论文

但两者都专注于坚持 Haskell 的非严格语义,但使用最严格的评估策略,而不是真正改变语义,而且都没有真正看到曙光。

编辑:Martijn 对 strict-plugin 的建议看起来非常适合您的目的,因为它实际上可以满足您的需求,而且作者仍然活跃在 Haskell 社区中,我已经忘记了。

【讨论】:

【参考方案4】:

另请参阅ghc-strict-plugin,GHC's plugin framework 的示例,在Monad Reader 12 中进行了描述。

【讨论】:

【参考方案5】:

我感觉到你的痛苦。我日常编程中最大的 PITA 是处理那些 !@#$%^&( 空间泄漏。

但是,如果它有帮助,随着时间的推移,您确实会(艰难地)学习如何处理这个问题,并且它确实会变得更好。但我仍在等待安迪吉尔拿出他神奇的空间泄漏分析器来解决我所有的问题。 (我在上一届 ICFP 上对我说他想出了这个很酷的想法作为实现它的承诺。)

我不会试图说服你懒惰的评估是世界上最好的事情,但它有一些好处。我有一些流处理程序,它们通过各种组合器在仅使用 3.5 MB 左右的内存(其中超过 2MB 是 GHC 运行时)上愉快地运行在千兆字节数据上的各种组合器中搜索惰性列表。去年有人向我指出,你会非常惊讶,作为一个典型的 Haskell 程序员,你对惰性求值的依赖程度。

但我们真正需要的是一本关于现实世界中处理惰性评估的非常好的书(这与学术界并没有太大的不同,真的,除了他们根本没有发表论文,而我们有客户用刀追我们),这将适当地涵盖与此相关的大多数问题,更重要的是,让我们直观地了解什么会爆炸我们的堆,什么不会。

我不认为这是新事物;我确信其他语言和架构也经历过这种情况。毕竟,第一批程序员是如何处理硬件堆栈的呢?不太好,我敢打赌。

【讨论】:

顺便说一句,您可以在 Template Haskell 的帮助下,制作各种 NFData 的实例,并严格限制 wazoo,很多很多次。我艰难地了解到,除了真正耗尽你的 CPU 缓存之外,这不是解决任何问题的最佳解决方案......【参考方案6】:

我认为 Jan-Willem Maessan 的 pH compiler 很严格。下一个最接近的是 Robert Ennal 对 ghc 5 的推测性评估分支。 spec_eval 分支并不严格,而是乐观地评估。我不知道其中任何一个是否仍然是当前/可用/等。

【讨论】:

【参考方案7】:

在任何地方都使用 nfdata 和 rnf 不是解决方案,因为这意味着重复遍历已经评估过的大型结构。

Ben Lippmeier 博士论文(关于 DDC)的介绍性章节是关于我所见过的对 Haskell 的最佳批评——它讨论了懒惰、破坏性更新、monad 转换器等问题。DDC 有懒惰,但你必须明确地请求它,它被认为是一个效果,由 DDC 的类型和效果系统跟踪和管理。

【讨论】:

【参考方案8】:

我最近看到了这方面的一些工作:

https://ghc.haskell.org/trac/ghc/wiki/StrictPragma

您可以在此处的 SPJ 的 GHC 状态更新中听到一些关于它的信息:

http://youtu.be/Ex79K4lvJno?t=9m33s (链接从 9:33 的相关部分开始)

【讨论】:

【参考方案9】:

我正在寻找一个默认使用严格评估而不是惰性评估的 Haskell 编译器。

这样的编译器不会是 Haskell 编译器。如果您真的需要,您可以考虑将-# LANGUAGE Strict #- 编译指示放入您的文件中。这将适用于 GHC 8.0.2、8.2.2 和 8.4.1,也就是编译器的最后三个版本。

如果有办法在某些地方也使用惰性求值也会很有帮助,以防万一我想要一个无限列表之类的东西

没有这样的方法。相反,按原意使用 GHC - 作为一种惰性语言。学会正确地思考你的代码、配置文件和使用函数式数据结构将比在任何地方盲目地应用严格性编译指示有用得多。 GHC 已经有一个严格分析器。

(我可能永远不会)。

这正是 llvm-hs thought 的作者选择使用严格状态单子而不是惰性单子时的原因。相反,它导致了一个意想不到的错误。惰性和递归齐头并进。

请不要试图说服我懒惰的评估更好,我真的需要性能。

我怀疑这实际上是您想要的,因为它不能可靠地提高 Haskell 代码的性能,同时破坏现有代码并使现有资源无用。如果你打算用这种方式编写程序,请使用 OCaml 或 Scala,别管 Haskell 社区。​​p>

IIRC,Simon Peyton Jones 甚至说惰性评估并不是真正必要的,它主要是为了防止他们使语言变得不纯。

那不是真的。你可以阅读更多关于 Haskell 的实际历史here

【讨论】:

【参考方案10】:

还有seqaid,它的目标是惰性严格范围的中间。

Seqaid 是一个 GHC 插件,提供 Haskell 项目的非侵入式自动检测,用于动态严格性(和并行性)控制。这将很快包括使用最小严格性对自动空间泄漏缓解进行优化。

【讨论】:

【参考方案11】:

您显然已经决定严格评估的价值,但我认为您错过了使用 Haskell 的意义。 Haskell 的惰性求值允许编译器/解释器采用更灵活的优化策略。强制您自己的严格性会覆盖优化器。最后,使用过度严格的评估永远不会像自动优化那样有效。尝试在 GHCI 中对一系列数字进行折叠求和,使用和不使用惰性求值。您可以很清楚地看到差异——在这种情况下,惰性求值总是更快。

【讨论】:

所有像 SPJ 等认真的 Haskell 人现在基本上都同意,虽然默认惰性是一项重要的研究工作,但严格默认是正确的方法,因为程序员需要推理关于他们代码的性能。我们基本上是在转动***,直到像 Idris 等 Haskell 的继任者找到足够多的开发人员、研究人员等来取代 Haskell 作为“下一个大型研究语言”。所有这些新的研究语言都是默认严格的,因为它们是从 Haskell 学习的。现在您可以随时在这些语言中使用惰性。 @JeffBurdges 请为您声称 SPJ 提倡“默认严格”的声明提供链接/资源。虽然我知道他很清楚懒惰的坏处,但我从未真正听过他说他后悔“默认懒惰”。 我从未断言 任何人 对 Haskell 中的惰性求值感到遗憾,只是惰性求值被理解为一个需要保持纯研究领域的主题,用于部署的语言应该使用严格的评估。在实践中,GHC 在与人类程序员竞争时过于频繁地做错了严格性。我认为这属于 Haskell 的口号“不惜一切代价避免成功”。 事实上,这里有一句 SPJ 更进一步说“下一个 Haskell 将是严格的”:news.ycombinator.com/item?id=1924061 让 Haskell 默认为惰性并不后悔,但仅仅是观察(1)他们从惰性中学到了很容易学到的东西,(2)编译器未能充分利用惰性,尽管这仍然是一个有趣的研究课题,以及(3)为了追求他们真正的纯洁性目标,他们应该建立一个继任者对 Haskell 来说,这并不懒惰。伊德里斯就是这样一种尝试。 @JeffBurdges 这根本不是对 SPJ 观点的准确描述,也不是共识。这是不明智的废话。

以上是关于是否有使用严格评估的 Haskell 编译器或预处理器?的主要内容,如果未能解决你的问题,请参考以下文章

在 Haskell 中自动插入惰性

Haskell如何强制在haskell中评估Data.Map?

Haskell 不会懒惰地评估交错

Haskell:使用严格性的指南

seq如何评估Haskell中的无限列表?

如何缓存或预渲染画布动画