我想知道 enum 类型类不继承 ord 类型类的原因。enum 中的 succ 函数本质上对值强加了一个顺序,但 ord 不是必需的约束。
编辑:此外,对于类型类中的其他函数,似乎有一个关于为它们定义 ord 运算符的隐含假设。如此处所示https://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#v:enumFromTo
一个可能的实现是 enumFromTo nm | n <= m = n : enumFromTo (succ n) m | 否则= []
类型类Ord旨在表示全序,其中需要传递性:ifa < b和b < c, then a < c。
超类对于类实例的定义应该是必需的。
尽管Enum它可能对其元素强加一个顺序(尽管不一定是全序),但它不使用或要求全序。
举个例子,考虑每个人最喜欢的决策算法:
data RPS = Rock | Paper | Scissors deriving (Eq, Ord)
instance Enum RPS where
succ Rock = Paper
succ Paper = Scissors
succ Scissors = Rock
Run Code Online (Sandbox Code Playgroud)
Ord从定义中导出的实例是完整的、直接的:是Rock最小的元素、Scissors最大的元素以及Paper介于两者之间的元素。
此枚举所隐含的顺序并不完整。给定succ,您可能会假设Rock < Paper和Paper < Scissors,但 thenRock < Scissors应该为真,这并不是所暗示的succ Scissors = Rock。
该Ord实例对于定义上面显示的内容没有用处Enum。
不幸的是,正确的实例声明应该使用toEnumand fromEnum,所有其他方法(包括succ)都可以从中派生。这使得定义更加冗长。遵循模型DaysOfWeek
instance Enum RPS where
-- *We* know that n `mod` 3 has 3 possible results, but
-- the exhaustivity checker does not, so use _ in place of 2
toEnum n = case n `mod` 3 of
0 -> Rock
1 -> Paper
_ -> Scissors
fromEnum Rock = 0
fromEnum Paper = 1
fromEnum Scissors = 2
-- The generated definitions don't handle wrapping. Without these,
-- [Paper..Rock] would produce [], not [Paper, Scissors, Rock].
enumFromTo wd1 wd2
| wd1 == wd2 = [wd1]
enumFromTo wd1 wd2 = wd1 : enumFromTo (succ wd1) wd2
enumFromThenTo wd1 wd2 wd3
| wd2 == wd3 = [wd1, wd2]
enumFromThenTo wd1 wd2 wd3 = wd1 : enumFromThenTo wd2 (toEnum $ (2 * fromEnum wd2) - (fromEnum wd1)) wd3
Run Code Online (Sandbox Code Playgroud)