我有一个获取数据的函数,它返回相同的数据或稍微修改过的版本。
我想让我的程序在发生变化时做一件事,或者如果它没有改变则做另一件事。
之前我正在返回一对(Bool,Object)
并使用fst
来检查它是否发生了变化。最近我想到我可以通过返回对象并使用==
检查相等来简化代码。
但后来我意识到Haskell没有区分深度相等检查和“对象身份”(即指针相等)。那么我怎么知道使用==
是否有效?我是否应该出于效率原因而避免使用它,或者是否存在依赖于编译器确定它不需要进行深度相等检查的情况?
通常我在编写初始程序时不会太担心效率,但这会影响我的模块的接口,所以我想在编写太多代码之前做到正确,而且似乎不值得做该程序只需要一小段代码就效率低得多。此外,我想更好地了解我可以依靠GHC进行哪种优化来帮助我。
答案 0 :(得分:34)
依靠不确定的编译器优化来提供诸如恒定时间相等与线性时间深度相等之类的重要性能保证始终是一个坏主意。使用封装值的新类型以及有关值是否为新的信息,您会好得多。根据您的应用程序,这可以是
data Changed a = Changed a | Unchanged a
或
data Changed a = Changed a | Unchanged
我们实际上在Glasgow Haskell编译器中使用了类似的类型,因此我们可以继续运行优化器,直到代码停止更改。我们还运行迭代数据流分析,直到结果停止变化。
我们发现将此类型设为monad非常有用,这样我们就可以使用do
表示法编写一些简单的高阶函数,但这不是必需的 - 只是方便。
摘要:如果您想要进行常量时间检查,请自行编码 - 不要依赖可能不存在的编译器优化 - 或者在下一版本中可能会更改。
答案 1 :(得分:4)
派生(==)总是深度比较。你的问题是discussed在haskell-cafe上。
答案 2 :(得分:1)
我仍然是一个亲戚haskell noob,所以请大家用我的答案,请原谅我,如果我的答案不是那么直接!
在Haskell中,运算符并不特殊 - 它们只是中缀函数。
您可以在标准前奏中查看definition of the equality operator。
当然,它可以重载以使用您定义的任何数据类型 - 但如果您执行重载,您将知道实现的效率。
知道您可以使用Hoogle查找所需的函数定义可能会有所帮助。这就是我找到相等运算符的定义。