如何测试Haskell对象的引用相等性?

3
在Haskell中,相等性测试通常使用==来自Eq类来执行。 这个函数(在大多数情况下)是在纯Haskell术语下定义的,因此它遵循将其递归应用于大型数据结构的所有后果。 因此,一个看似微不足道的比较可能需要相当长的时间。 意识到惰性,这应该是即时的:
ghci> let x = [1..100000000] in x == x
True
(2.81 secs, 14,400,130,800 bytes)

为什么 Haskell 这里不使用引用比较?如果我确实想这样做,Haskell 是否允许我这样做呢?

2
不,它使用一种称为“引用透明度”的概念,这意味着您无法看到将产生输出的表达式与实际输出之间的区别。这很重要,否则它可能被用作某些后门机制来使函数变得不纯 - Willem Van Onsem
1
你会提供这样的后门吗? - radrow
1
最主要的是它使评估可观察。如果我有 xs = [1, 2, 3]ys = id xs,然后稍后我问 xs == ys,如果 == 意味着指针比较,那么根据 ys 是否被评估,我会得到不同的结果。如果这是可观察的,那么我们需要仔细定义 何时 可以进行评估,以便我们可以确保评估 xs == ys 的结果是可预测的。这基本上迫使我们成为一种命令式语言,其中代码作为一系列步骤,而不是“无时间”的表达式语言。此外,它排除了许多编译器优化。 - Ben
有点离题,不要在GHCi中计时,因为代码没有像编译后的代码那样进行优化,在那里你真正关心性能。 - chepner
你可能会对 reallyUnsafePtrEquality# 和以下其他问题感兴趣:https://dev59.com/fWkw5IYBdhLWcg3wyNgV,https://dev59.com/emIk5IYBdhLWcg3wWs9z,https://stackoverflow.com/q/30175974,https://stackoverflow.com/q/48163259。 - Taylor Fausak
2个回答

11
短答案:在Haskell中不可能实现这一点,这是有很好的理由的。参考相等性是语言设计的基本部分,保留它使得Haskell与许多其他语言在语言设计空间中有所不同。
稍微长一点的答案:这是一个经过深入研究的主题,通常被称为可观察共享,可以追溯至至少2000年代初:
  • Claessen和Sands解释了什么情况下Observable Sharing有用以及如何将其纳入语言中。这是一篇非常易于阅读的论文,详细解释了问题并提出了一种非保守的扩展。适合理解基本问题。

  • Gill的解决方案是实践中使用的一个非常可行的方法,称为type-safe observable sharing。这里的想法是您可以在纯代码中创建等式,但只能在单调IO上下文中观察它们; 这样可以保留引用相等性。它没有错误的负面影响,几乎没有错误的正面影响。还有一个实现该想法的hackage,您可以随时使用。

长话短说:对于非常好的原因,在Haskell中你不能进行引用相等性、指针相等性或直接观察共享。这个问题已经得到了深入研究和理解,并且在不破坏引用透明性的情况下,有实际的解决方案来解决Haskell生态系统中的这个问题。

0
如果您正在寻找一种替代比较引用以加快相等性计算的方法,请尝试System.Mem.StableName。两个对象的StableNames的相等性保证这两个对象实际上是同一个对象。但是不等式并不意味着任何事情,因为对象可以被运行时系统复制和移动。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接