【问题标题】:Efficiency of equality in HaskellHaskell中的平等效率
【发布时间】:2009-12-29 18:53:48
【问题描述】:

我有一个函数,它接收数据并返回相同的数据或稍作修改的版本。

我想让我的程序在它改变时做一件事,如果它没有改变,我想让它做另一件事。

以前我返回一对(Bool,Object) 并使用fst 检查它是否改变了。最近我突然想到,我可以通过返回对象并使用==检查是否相等来简化代码。

但后来我意识到 Haskell 并没有区分深度相等检查和“对象标识”(即指针相等)。那么我怎么知道使用== 是否有效呢?我应该出于效率原因避免它,还是在某些情况下我可以依赖编译器来确定它不需要进行深度相等检查?

通常我在编写初始程序时不会太担心效率,但这会影响到我的模块的接口,所以我想在编写太多代码之前把它做好,而且似乎不值得做该程序的效率要低得多,只需一小段代码。此外,我想更好地了解我可以依靠 GHC 来帮助我进行哪些优化。

【问题讨论】:

  • 请注意,对于 Either 值或等效但更语义化的值(例如 data ChangeState a = Same a | Changed a),这似乎是一个更好的情况。

标签: performance haskell


【解决方案1】:

依赖不确定的编译器优化来提供诸如常量时间相等与线性时间深度相等之类的重要性能保证总是一个坏主意。使用封装值以及有关该值是否为新的信息的新类型会更好。根据您的应用程序,这可以是

data Changed a = Changed a | Unchanged a

data Changed a = Changed a | Unchanged

我们实际上在 Glasgow Haskell 编译器中使用了类似的类型,因此我们可以继续运行优化器,直到代码停止更改。我们还运行迭代数据流分析,直到结果停止变化。

我们发现将这种类型设为 monad 很有用,这样我们就可以使用 do 表示法编写一些简单的高阶函数,但这不是必需的——只是为了方便。

总结:如果您想要进行常量时间检查,请自己编写代码——不要依赖可能不存在的编译器优化——或者可能会在下一个版本中更改。 p>

【讨论】:

  • 谢谢,这感觉是一个非常具体的答案。
  • 我想知道它是如何作为 monad 工作的?第二个版本看起来像 Maybe monad。然而,与Maybe 不同的是,在这里您想要最后一个未更改的结果,而不仅仅是知道它是后来的Unchanged
  • @yairchu 它仍然有点类似于 Maybe monad。如果单子组合中的任何地方都有“已更改”,则结果为“已更改”,否则为“未更改”
【解决方案2】:

派生的 (==) 始终是深度比较。您的问题是在 haskell-cafe 上的discussed

【讨论】:

    【解决方案3】:

    我仍然是一个相对的haskell菜鸟,所以请对我的回答持保留态度,如果我的回答没有应有的直接,请原谅我!

    在 Haskell 中,运算符并不特殊 - 它们只是中缀函数。

    你可以在标准前奏中查看definition of the equality operator自己。

    当然,它可以被重载以使用您定义的任何数据类型 - 但如果您进行重载,您就会知道实现的效率有多高。

    知道您可以使用Hoogle 查找所需的函数定义可能会有所帮助。这就是我找到相等运算符的定义的方式。

    【讨论】:

    猜你喜欢
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-08
    • 1970-01-01
    相关资源
    最近更新 更多