如何在Haskell中实现代数数据类型的“Ord”?

时间:2011-08-16 14:07:59

标签: haskell

想象一下,你有一个像

这样的评级
Rating = OneStar | TwoStars | ThreeStars | FourStars | FiveStars

在Haskell中为这样的代数数据类型实例化/实现“Ord”的最佳方法是什么?

4 个答案:

答案 0 :(得分:15)

最好的方法是将deriving (Eq, Ord)添加到类型的定义中。

由于您按升序列出了构造函数,派生的Ord实例将为您提供所需的命令。

但是,如果由于某种原因更改定义中的顺序不是一个选项,您仍然可以导出Eq,因为顺序无关紧要。给定Eq的实例,我们可以手动为Ord编写实例。定义比较最简洁的方法可能是拼出比较应返回LT的所有组合,然后简单地使用compare x y | x == y = Eq;比较_ _ = GT表示其余组合。

答案 1 :(得分:3)

如前所述,您可以派生EqOrd。或者你可以派生Enum,然后做

instance Eq Rating where
    x == y = fromEnum x == fromEnum y

或者只是拼写出来

instance Eq Rating where
    OneStar == OneStar = True
    TwoStar == TwoStar = True
...
    _ == _ = False

答案 2 :(得分:0)

对于任何想知道的人,这是完整的,明确的样板实现:

使用罗马数字。
使用case易于阅读。

data RN = I | II | III | IV | V

instance Eq RN where
    I == I     = True
    I == _     = False
    II == II   = True
    II == _    = False
    III == III = True
    III == _   = False
    IV == IV   = True
    IV == _    = False
    V == V     = True
    V == _     = False

instance Ord RN where
    compare I x = case x of
        I   -> EQ
        _   -> LT
    compare II x = case x of
        I   -> GT
        II  -> EQ
        _   -> LT
    compare III x = case x of
        I   -> GT
        II  -> GT
        III -> EQ
        _   -> LT
    compare IV x = case x of
        V   -> LT
        IV  -> EQ
        _   -> GT
    compare V x = case x of
        V   -> EQ
        _   -> GT

答案 3 :(得分:0)

另一种实现 compare 的方法是使用已经是 Ord 实例的类型。

data Rating = OneStar | TwoStars | ThreeStars | FourStars | FiveStars
    deriving (Show, Eq)

instance Ord Rating where
  compare x y = compare (r2n x) (r2n y)
    where
      r2n OneStar = 1
      r2n TwoStars = 2
      r2n ThreeStars = 3
      r2n FourStars = 4
      r2n FiveStars = 5

我认为这个解决方案的扩展性很好。