【问题标题】:Non-lazy branch of GHCGHC的非懒惰分支
【发布时间】:2012-06-02 18:57:20
【问题描述】:

我听说有一个 GHC 的分支默认编译成严格的代码,而惰性可以通过注释来启用。 (IIRC,他说一家金融公司开发分支并将其用于生产代码。)这是真的吗?没找到。

此人还建议,严格评估比惰性评估(默认情况下)更实用的观点越来越得到认可。 我在 Haskell 邮件列表中没有发现这一点,但可能是因为那里的人不注重实践?

我在严格的 Haskell 上找到的都是明确的东西,比如 $!rnf。虽然我发现惰性求值非常优雅,但我想在 Haskell 中开发一个程序,我想避免空间泄漏并希望获得可预测的性能。

免责声明:我不是在为严格辩护,我只是想看看严格的 Haskell 或类似的东西。

【问题讨论】:

  • 通过(公认的愚蠢表达)粗鲁的惊喜,我的意思是空间泄漏和运行时的不可预测性。其实我没有遇到过,但在我看来这些问题是真实存在的,对吧? (我目前正在评估使用哪种语言。)
  • 我认为这可能被称为Mu? Lennart Augustsson 可能在某处提到过。
  • 当然,瑞士信贷已经建立了一个基于 Haskell 的财务建模系统,称为天堂项目。我相信 Augustsson 教授可能已经对此进行了研究。我也相信团队中的大部分人,包括 Augustsson 教授,后来都搬到了渣打银行……
  • 这是很棒的信息,jtobin 和循环破坏!非常感谢,我正在调查。
  • 2002 年,有一个Jan-Willem Maessen's dissertation on "Eager Haskell"(论文现在处于死链接)。更多关于“渴望 Haskell”here。它似乎已经沉没了,好吧,从那时起就一直如此。

标签: haskell ghc


【解决方案1】:

您正在寻找Disciple

所以在 Haskell 中有两种懒惰需要区分。有惰性 I/O,这是一种可憎的事情,由 iteratee 库解决(无耻插件:包括我的 pipes 库)。然后是纯计算中的惰性,这仍然存在争议,但我将尝试总结惰性的主要优点,因为您已经熟悉缺点:

懒惰更有效率

一个简单的例子是:

any = foldr (||) False

any 查找列表中的任何值是否为True。这只会评估直到第一个 True 的元素,因此列表是否很长并不重要。

惰性只计算它必须的量,这意味着如果将两个惰性计算链接在一起,它实际上可以提高计算结果的时间复杂度。 This Stack Overflow comment 给出了另一个很好的例子。

这实际上是 iteratee 库非常节省资源的原因。他们只做尽可能多的工作来生成结果,这会导致非常有效的内存和磁盘使用以及非常易于使用的语义。

懒惰本质上更易于组合

使用严格和函数式编程的人都知道这一点,但实际上我在处理 pipes 库时无意中证明了这一点,其中惰性版本是唯一允许 @ 的版本987654330@ 实例。管道实际上可以在任何 monad 中工作,包括纯 Identity monad,所以我的证明也可以转换为纯代码。

这就是为什么我认为一般的惰性确实是编程的未来的真正原因,但是我仍然认为 Haskell 是否“正确”实现了惰性是一个悬而未决的问题。

【讨论】:

  • 一个很好地处理这个话题的视频讲座是免费提供的here。 (注:视频为英文,我与视频或亚琛大学无关)
  • 我认为惰性的主要优点是它提供了灵活性和关注点分离。在想要被认为是声明性的语言中,它也是默认的。在理想的 haskell 中,它的评估模型只是一个实现细节。
  • @jberryman 对,我想说的是,这种“灵活性”和“关注点分离”的直觉可以通过说只有懒惰构成一个类别来变得严格。
  • “有惰性 I/O,令人讨厌”。啊。我是 Haskell 的新手,但是阅读关于惰性 I/O 的文章让我想到了一个由在幕后构建的管道链接的流处理代理网络的图像,一旦需要输出,它就开始了它的所有(非确定性)荣耀.不确定这是否是实际完成的方式。
【解决方案2】:

如果我理解正确的话,严格的 Haskell 不可能有我们所知道的单子 I/O。 Haskell 中的想法是所有 Haskell 代码都是纯代码(包括 IO 操作,其工作方式类似于 State monad),并且“main”将 IO () 类型的值提供给运行时,然后反复强制排序运算符 >>= .

要与 Tekmo 的帖子相对立,您可以查看 Robert Harper 的博客, * http://existentialtype.wordpress.com/2011/04/24/the-real-point-of-laziness/ 和相关的。它是双向的。

根据我的经验,懒惰一开始很难,但你习惯了就没事了。

关于惰性的经典宣传文章是 Hughes 的论文“为什么函数式编程很重要”,您应该可以轻松找到它。

【讨论】:

  • Monadic IO 不依赖懒惰。
  • 你不需要强制>>=; getLine >>= putStrLn 是一个完全独立的表达式,产生一个执行其所说的操作,您可以在实际执行 IO 操作之前对其进行全面评估。
【解决方案3】:

关于为什么你不应该回避 Haskell 的懒惰已经说了一些好话,但我觉得最初的问题仍未得到解答。

Haskell 中的函数应用是非严格的;也就是说,仅在需要时才评估函数参数。

~Haskell Report 2010 > Predefined Types and Classes # Strict Evaluation

不过,这有点误导。实现可以在需要之前评估函数参数,但仅限于有限的范围。您必须保留非严格语义:因此,如果参数的表达式导致无限循环,并且未使用该参数,则使用该参数的函数调用不得无限循环。

所以你被允许以一种不完全“懒惰”的方式实现 Haskell,但它也不能是“严格”的。乍一看,这似乎是一个矛盾,但事实并非如此。您可能想查看一些相关主题:

【讨论】:

    【解决方案4】:

    听起来您好像听说过 Robert Ennals 与 GHC 合作的 PhD thesis on speculative evaluation。他创建了 GHC 的一个分支,称为“spec_eval”分支,其中进行了推测评估。因为 Haskell 是非严格的而不是显式的惰性,所以 spec_eval 严格到它实际有所作为的程度。虽然它在所有情况下都更快,但它需要对 GHC 进行大量更改并且从未合并。

    这个问题在这个网站上有某种been answered before

    【讨论】:

      【解决方案5】:

      我听说有一个 GHC 的分支默认编译成严格的代码,而懒惰可以通过注解来启用

      您可以尝试 GHC 8.0.2、8.2.2 或 8.4.1,也就是最后三个版本中的任何一个。他们有一个{-# LANGUAGE Strict #-} pragma 用于数字代码等。

      金融公司开发分支并将其用于生产代码。)这是真的吗?没找到。

      Standard Chartered 确实开发了自己的 Haskell 编译器。我不希望他们将其提供给公众。我不确定默认情况下是否严格。

      该人还提出了严格评估比懒惰评估更实用的观点

      这没有意义,也没有证据支持。事实上,llvm-hs-pure 包通过选择使用 state monad 的严格版本而不是惰性版本来引入bug。此外,parallel-io 包之类的东西也不起作用。

      我想在 Haskell 中开发一个程序,我想避免空间泄漏并希望获得可预测的性能。

      这两年没被偷懒导致的空间泄露给咬过。我建议改为使用基准测试并分析您的应用程序。编写具有可预测性能的 Haskell 比添加严格注释并希望您的程序仍然可以编译更容易。理解程序、分析和学习函数式数据结构比盲目地添加编译器编译指示来提高程序的性能会为您提供更好的服务。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-22
        • 2016-07-24
        • 2015-09-06
        相关资源
        最近更新 更多