为什么 enum 类型类不是 ord 类型类的子类?

jud*_*ude 5 haskell typeclass

我想知道 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 | 否则= []

che*_*ner 1

类型类Ord旨在表示序,其中需要传递性:ifa < bb < 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 < PaperPaper < 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)