Haskell:标准库假设Eq和Ord兼容吗?

时间:2013-12-16 19:31:52

标签: haskell typeclass

这是Inconsistent Eq and Ord instances?的后续问题。

问题基本上是:在为某个类型声明EqOrd个实例时,必须确保compare x y返回EQ当且仅当{{1} }返回x == y?创建打破这种假设的实例是危险的吗?这似乎是一个人们可能会假设的自然法则,但它似乎没有在前奏中明确说明,不像monad或functor law。

基本的回答是:这样做有点危险,因为图书馆可能认为这项法律有效。

我现在的问题是:做任何标准库(特别是TrueSet)做出这个假设吗?如果我只依赖GHC提供的标准库,那么拥有一个不兼容MapEq的类型会很危险吗?(如果仍然可以接受大名单问题,我会问:哪些常用的库假定这个定律?)

编辑。我的用例类似于原始问题的用例。我有一个自定义实例Ord的类型,我使用了很多。我想要Eq的唯一原因是我可以将其用作Ord的域名;我不关心具体的顺序,也绝不会在代码中明确使用它。因此,如果我可以使用Map的派生实例,那么我的生活会更轻松,代码也会更清晰。

3 个答案:

答案 0 :(得分:6)

OrdEq本身的定义要求已有class (Eq a) => Ord a where ... 个实例:

    x == y           =  compare x y == EQ
    x /= y           =  compare x y /= EQ

所以违反

就是错误的
    x <= y           =  compare x y /= GT
    x <  y           =  compare x y == LT
    x >= y           =  compare x y /= LT
    x >  y           =  compare x y == GT

违反(从Ord中这些运算符的默认定义)。

Ord

编辑:在库中使用

如果标准库没有使用==的{​​{1}}和/=运算符,我会感到非常惊讶。特定目的运算符(==/=<=<>=>)通常比{{1}更方便},所以我希望在comparemap s的代码中看到它们。

你可以standard prelude。此特定功能仅调用filter类,但如果该键也是Eq个实例,则Ord的{​​{1}}将用于结果的其他功能Ord,假设compare的{​​{1}}与Map的{​​{1}}相同并且正在测试Eq

作为一名图书馆程序员,如果任何特殊目的操作员出于特定目的而优于==,我不会感到惊讶。毕竟,这就是为什么它们是Ordcompare类的一部分,而不是被定义为所有EQcompare实例的多态。即使Eq更方便,我也可能会使用它们。如果我这样做,我可能会定义类似的东西:

Ord

答案 1 :(得分:3)

为了扩展Cirdec的答案,只有在定义的操作以某种方式 canonical 时才应该生成类型类实例。如果合理的Eq未延伸到合理的Ord,那么最佳做法是选择其他Eq或不定义Ord。为“其他”平等创建非多态函数很容易。

这种紧张的一个很好的例子是潜在的Monoid实例

instance Monoid Int where
  mzero = 0
  mappend = (+)

与其他“明显的”Monoid实例竞争

instance Monoid Int where
  mzero = 1
  mappend = (*)

在这种情况下,选择的路径既不是实例化,也不是因为不清楚一个是“规范”而不是另一个。这通常最符合用户的期望,并防止错误。

答案 2 :(得分:1)

我已经阅读了这个和你原来的问题,所以我会解决你的一般问题......

你想要这个 -

Map BigThing OtherType

和 -

(==)::BigThing->BigThing->Bool

其中一个案例必须准确,另一个案例应该忽略一些数据,这是出于性能原因。 (这是(==)在第一个问题中需要准确,但看起来你可能正在解决这个问题的反面......无论哪种方式都是相同的答案。)

例如,您希望地图仅基于某个标签存储结果,例如

`name::BigThing->String`

但是(==)应该进行深度比较。一种方法是定义不兼容的compare(==)函数。然而....

在这种情况下,这是不必要的。为什么不直接使用地图

Map String OtherThing

并像这样进行查找 -

lookup (name obj) theMap

很难直接索引非常大的文档数据....