为什么Eq类存在?

V. *_*ria -2 haskell

假设我想定义Mod4模4的整数类型.毕竟,Int是Mod2^64.我能走的一个显而易见的方法是

data Mod4 = ZeroMod4 | OneMod4 | TwoMod4 | ThreeMod4 
Run Code Online (Sandbox Code Playgroud)

不过我也可以这样做

data Mod4 = Mod4 Integer

instance Eq Mod4 where
  (Mod4 x) == (Mod4 y) = (x-y) `mod` 4 == 0
Run Code Online (Sandbox Code Playgroud)

但是这个功能有问题:

f :: Mod4 -> Mod4
f (Mod4 x) = if x < 20 then Mod4 0 else Mod4 1
Run Code Online (Sandbox Code Playgroud)

f (Mod4 16)不同于f (Mod4 20),而这两个论点是==.所以我最终得到了两种平等:在记忆中的表现( Mod4 16不同于Mod4 20)和==.

由于所有函数都可以匹配其参数,因此它们始终可以绕过任何==运算符.为什么Haskell没有将内存中的表示作为平等的定义?这样所有类型都变得平凡.

实际上,功能的概念暗示了平等:在给定相等输入时产生相等输出的图形.因此,谈论一个不相等的类型的函数是没有意义的.

chi*_*chi 10

为什么Haskell没有将内存中的表示作为平等的定义?这样所有类型都变得平凡.

不.您无法比较类型的值Integer -> Bool.通常,无法比较函数.

回到黑板上.如何用打字语言设计平等?

一个选项是let (==) :: a -> a -> Bool,如果a是函数则抛出异常.参见例如Ocaml.

另一个选择是在equatable/not equatable中分区类型.这是eqtype在SML中.

另一个但相关的选择是将"eq-ability"表达为对多态性的约束.Eq在哈斯克尔.

现在,Eq可能会更特别.例如,你不能自己定义它的实例,你必须使用deriving Eq,类似于Typeable现在的工作方式.而Haskell设计者则允许用户定义自己的比较函数.用户可能会知道一些"更聪明"的方式.例如,为了比较10场记录,首先比较通常不同的字段,然后比较通常相等的字段,试图提高效率.

请注意,如果我们不导出数据类型构造函数,我们可以使等式成为等价并且仍然有用.例如,Data.Set.Set当它们代表相同的集合时,它们等同于不同的(平衡的)树,但是导出的接口永远不会破坏等价,所以相等看起来像是来自外部的相等.

因此,谈论一个不相等的类型的函数是没有意义的.

的确,当"不等于"在数学意义上被解释时.然而.当它被解释为"等式谓词不可计算"时,它很有意义.我们可以谈论一个函数,它处理类型具有不可判定的相等性的值.

  • @ V.Semeria,这里的`Data.Set`示例chi代表了一个非常常见的情况.*大多数*有趣的数据结构具有一定量的"冗余",允许同一抽象对象的多个具体表示.`Data.Set`,`Data.Map`,`Data.Sequence`,`fgl`中的图形类型,绳索,堆,矢量切片,各种B树变体,功能队列,deques,输出限制deques ,可连续的deques,monoidal指树等,都具有非结构性的平等. (6认同)