这是Inconsistent Eq and Ord instances?的后续问题。
问题基本上是:在为某个类型声明Eq
和Ord
个实例时,必须确保compare x y
返回EQ
当且仅当{{1} }返回x == y
?创建打破这种假设的实例是危险的吗?这似乎是一个人们可能会假设的自然法则,但它似乎没有在前奏中明确说明,不像monad或functor law。
基本的回答是:这样做有点危险,因为图书馆可能认为这项法律有效。
我现在的问题是:做任何标准库(特别是True
或Set
)做出这个假设吗?如果我只依赖GHC提供的标准库,那么拥有一个不兼容Map
和Eq
的类型会很危险吗?(如果仍然可以接受大名单问题,我会问:哪些常用的库假定这个定律?)
编辑。我的用例类似于原始问题的用例。我有一个自定义实例Ord
的类型,我使用了很多。我想要Eq
的唯一原因是我可以将其用作Ord
的域名;我不关心具体的顺序,也绝不会在代码中明确使用它。因此,如果我可以使用Map
的派生实例,那么我的生活会更轻松,代码也会更清晰。
答案 0 :(得分:6)
Ord
中Eq
本身的定义要求已有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}更方便},所以我希望在compare
或map
s的代码中看到它们。
你可以standard prelude。此特定功能仅调用filter
类,但如果该键也是Eq
个实例,则Ord
的{{1}}将用于结果的其他功能Ord
,假设compare
的{{1}}与Map
的{{1}}相同并且正在测试Eq
。
作为一名图书馆程序员,如果任何特殊目的操作员出于特定目的而优于==
,我不会感到惊讶。毕竟,这就是为什么它们是Ord
和compare
类的一部分,而不是被定义为所有EQ
或compare
实例的多态。即使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
很难直接索引非常大的文档数据....