【问题标题】:turn off lazy evaluation in haskell在haskell中关闭惰性求值
【发布时间】:2016-09-08 00:57:49
【问题描述】:

是否可以在 Haskell 中关闭惰性求值?

库是否有特定的编译器标志来促进这一点?

我想用我不久前编写的旧程序尝试一些新的东西,看看我是否可以提高性能。

【问题讨论】:

  • 它是语言伙伴的一部分,处于最深层次。你有什么特别想渴望的吗?
  • 是否可以关闭 C 语言中的严格评估?我希望不会,至少在没有对语言语义进行深入的重新设计的情况下不会。当然,可以对 C 中的特定表达式实现某种惰性求值。所有这些语句对于 Haskell 也是如此,除了“严格”​​和“惰性”互换。
  • @Yitz - 现实世界的计算机使用严格的评估。编译器不需要努力工作来严格评估 - 他们需要努力工作(添加 thunk、延迟评估、严格分析以确定哪些地方没有必要)来支持惰性。 GHCs 作者花了很长时间来控制这些开销,尽管如此,严格的语言比同一语言的惰性版本更具有引用透明性 - 惰性意味着时间和空间复杂性由于延迟计算和引用不透明用于跟踪它们的可变数据结构。
  • @Yitz - 普遍的惰性求值在交互式和实时程序中尤其成问题。懒惰不是在有足够时间的时候做工作,而是将工作推迟到需要结果的时候——根据定义,当已经太晚了。当然,Haskell 中有一些具有选择性严格性的解决方法,但这并不是微不足道的——例如$! 仅将 strict 参数强制为 head-normal 形式 - 将其用于列表,其成员仍会被延迟评估。
  • @Steve314 - 不,真正的计算机使用编译器将它们编译成的任何语义。在硬件层面,现代处理器的语义与 C 的命令式模型的差距几乎与它们与 Haskell 的非严格模型的差距一样大。在任何成熟的语言中,有经验的程序员都可以优化到与硬件平台匹配所需的任何级别,同时仍然尽可能地受益于语言的优势,Haskell 也不例外。在 Haskell 中并不比在 C 中更难。

标签: haskell


【解决方案1】:

有很多方法可以让懒惰的事情变得严格。你可以:

  1. 显式插入虚假模式匹配。
  2. 使用seq或其近亲($!)
  3. 使用BangPatterns
  4. 对您的类型使用严格注释。

更多信息here

【讨论】:

  • 什么是虚假模式匹配?
  • @NikitaVolkov 例如,对于列表,将 foo 替换为 case xs of [] -> foo; _:_ -> foo
  • 使用 seq$! 不会强制对整个表达式进行完全评估 - 它只会强制“头部正常形式”。例如,在您的列表计算中使用seq,它会急切地评估结果列表——但这正是“cons”包含列表的头项的地方。头成员和整个尾列表可能尚未评估。要强制对完整表达式进行完全评估,一个选项是deepseq,这意味着您需要实例化NFData 类型类。另一个是为结果类型量身定制的严格强制函数。
  • 严格的Data.ByteString是另一个
【解决方案2】:

你不能关闭惰性,因为 Haskell 的 I/O 系统依赖于它。如果没有惰性求值,这个程序将运行到一个繁忙的循环中而不会输出任何东西:

main = forever (putStrLn "Hello!")

这是因为forever c 是一个无限程序。使用惰性求值时,程序仅在运行下一条指令所需的范围内计算。如果关闭惰性,每个函数都变得严格,包括(>>),这基本上使forever函数发散:

forever c = let cs = c >> cs in cs

但是,您可以向构造函数和模式添加严格注解。当一个函数是严格的时,它的参数被强制作为结果评估的一部分,与是否需要参数无关。这类似于热切评估。

【讨论】:

  • 这并不能证明你不能关闭惰性 - 它只是证明你可以关闭惰性并仍然让它们工作的程序集受到严重限制。 forever 只是一个特别明显的问题函数——有许多不太明显的函数会导致类似的问题——但是一个足够痴迷的人可能能够识别和使用仍然可以在禁用惰性的情况下使用的 Haskell 子集。无论如何 +1 - 这仍然是一个好点。
  • 您可以将 forever 定义为 forever c = c >>= \_ -> forever c,即使经过严格评估也可以使用。
【解决方案3】:

除了 Daniel Wagner 列出的内容之外,您可能还想看看类似的问题 Is there a Haskell compiler or preprocessor that uses strict evaluation?

  • 答案包括 DDC 编译器,它尝试制作严格版本的 haskell,并且只显式地惰性化
  • ghc plugin 描述于 monad.reader 12
  • “到处使用 nfdata 和 rnf” - solrize
  • 等等

主要的建议是使用分析工具并学习如何优化 Haskell,因为大多数人会认为它是一种关闭非严格评估的不同语言。

【讨论】:

    【解决方案4】:

    Haskell 有一个变体,称为 pH (http://csg.csail.mit.edu/projects/languages/ph.shtml) 它使用了急切的评估,同时仍然提供非严格的语义。 Haskell 报告谨慎地说它是一种非严格的语言。懒惰是描述和实施非严格性的明显方式。

    因此,如果您的问题是“我们能否在保持非严格语义的同时使用不同的评估系统”,您可以查看 pH。如果您的问题是“是否有一个版本的 Haskell 共享表面语法但默认情况下是严格的”,我认为它已被其他答案所涵盖。

    【讨论】:

      【解决方案5】:

      您可以在模块中启用Strict pragma,这将导致默认情况下所有内容都是严格的。

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

      【讨论】:

        【解决方案6】:

        简单的答案是否定的。更复杂的答案是 Haskell 建立和评估函数的计算模型以惰性方式工作。正如您将在其他答案中读到的那样,有一些方法可以比正常情况更早地强制评估某些功能,而且这样做有时是偶然的。但是有很大一部分有效的 Haskell 没有范式。这包括IO函数和大量的标准前奏。

        结论:没有办法在 Haskell 中关闭惰性求值,然后在 C 中关闭指针运算或在 Java 的 Ruby 中关闭 OO。我怀疑这比你要远得多,尽管这个问题会带你去。 (没有--strict 模式),但如果你真的想看看兔子洞有多深,Simon Peyton Jones 的“Implementing Lazy Functional Languages on Stock Hardware: The Spineless Tagless G-machine”是一次值得一试的冒险。

        【讨论】:

        • 您有该论文的更新链接吗?列出的那个坏了。
        【解决方案7】:

        strict-identity 包具有 Identity monad 的严格版本。

        您可以在这里找到它: https://hackage.haskell.org/package/strict-identity

        用法如下所示:

        foo = runStrictIdentity $! do
            x <- f a b
            y <- g x y
            return $! x + y
        

        每次使用return 或绑定&gt;&gt;= 时,都会使用seq 评估这两个部分,只要您的数据结构不太深,就可以合理保证严格性。这适用于数字和基本结构。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-05
          • 2014-11-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多