假设我想定义模数为4的整数类型Mod4
。毕竟,Int是Mod2^64
。我可以采取的一个显而易见的方法是
data Mod4 = ZeroMod4 | OneMod4 | TwoMod4 | ThreeMod4
但我也可以这样做
data Mod4 = Mod4 Integer
instance Eq Mod4 where
(Mod4 x) == (Mod4 y) = (x-y) `mod` 4 == 0
但是这个功能有问题:
f :: Mod4 -> Mod4
f (Mod4 x) = if x < 20 then Mod4 0 else Mod4 1
f (Mod4 16)
与f (Mod4 20)
不同,而这两个参数为==
。所以我最终得到了两种平等:在记忆中的表现(
Mod4 16
与Mod4 20
)和==
不同。
由于所有函数都可以模式匹配其参数,因此它们始终可以绕过任何==
运算符。为什么Haskell没有将内存中的表示作为平等的定义?这样,所有类型都变得平凡。
实际上,功能的概念暗示了平等:在给定相等输入时产生相等输出的图形。因此,在一个不相等的类型上谈论函数是没有意义的。
答案 0 :(得分:10)
为什么Haskell没有将内存中的表示作为相等的定义?这样,所有类型都变得平凡。
不。您无法比较Integer -> Bool
类型的值。通常,无法比较函数。
回到黑板上。如何用类型化语言设计相等性?
一个选项是让(==) :: a -> a -> Bool
,如果a
是一个函数,则抛出异常。参见例如ocaml的。
另一种选择是在equatable / not equatable中分区类型。这是SML中的eqtype
。
另一个但相关的选择是将“eq-ability”表达为对多态性的约束。 Haskell中的Eq
。
现在,Eq
可能更加特别。例如。您无法自己定义其实例,并且必须使用deriving Eq
,类似于Typeable
现在的工作方式。
而Haskell设计者则允许用户定义自己的比较函数。用户可能会知道一些“更聪明”的方式。例如。比较一个10场的记录,首先比较通常不同的字段,然后比较通常相等的字段,试图提高效率。
请注意,如果我们不导出数据类型构造函数,我们可以使等式成为等价并且仍然有用。例如。当Data.Set.Set
表示同一个集合时,$( "#menu-button" ).click(function() {
$("#right-sidebar").toggleClass("display");
if($("#right-sidebar").hasClass("display") == false){
$("#right-sidebar").css(opacity = "0");
} else {
$("#right-sidebar").animate({
opacity: "1"
}, "slow");
}
});
等同于不同的(平衡)树,但导出的接口永远不会破坏等价,所以相等看起来就像来自外部的相等。
因此,谈论一个不相等的类型的函数是没有意义的。
是的,当“不等于”在数学意义上解释时。然而。当它被解释为“等式谓词不可计算”时,它很有意义。我们可以谈论一个函数,它处理类型具有不可判定的相等性的值。