想象一下你有一个像这样的评分
Rating = OneStar | TwoStars | ThreeStars | FourStars | FiveStars
什么是在Haskell中实例化/实现“Ord”用于这种代数数据类型的最佳方法?
想象一下你有一个像这样的评分
Rating = OneStar | TwoStars | ThreeStars | FourStars | FiveStars
deriving (Eq, Ord)
。由于您按升序列出了构造函数,派生的Ord
实例将给出您想要的确切顺序。但是,如果定义的顺序与所需的比较顺序不匹配且出于某种原因无法更改定义的顺序,则仍然可以派生Eq
,因为对于这个不需要考虑顺序。给定Eq
的实例,我们可以手动编写一个Ord
的实例。定义compare
最简洁的方式可能是拼写应返回LT
的所有组合,然后对于剩余的组合,只需使用compare x y | x == y = Eq; compare _ _ = GT
即可。正如已经提到的,您可以推导出Eq
和Ord
。或者您可以推导出Enum
,然后执行
instance Eq Rating where
x == y = fromEnum x == fromEnum y
instance Eq Rating where
OneStar == OneStar = True
TwoStar == TwoStar = True
...
_ == _ = False
另一种实现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
我认为这个解决方案的可扩展性相当不错。
compare
(假设由于某些原因更改定义中的顺序不是选项)- 但您仍然可以派生Eq,因为对于它来说顺序并不重要。最简洁的定义compare
的方法可能是拼写出所有应返回LT的组合,然后对于其余组合只需使用compare x y | x == y = Eq; compare _ _ = GT
即可。 - sepp2kdata x = Val0 | Val1 | Val2 | Unused3 | Unused4 | Val5
。有时这是最快,最简单的方法,但如果有很大的间隔,显然不是最好的选择。 - Thomas M. DuBuisson