假设我有类似以下的数据类型:
data Foo = Foo { field1, field2, field3 :: Int }
我希望通过按特定顺序比较Ord
,field1
和field2
来使其成为field3
的实例。
我觉得写起来非常烦人:
-- (we need Eq Foo to define Ord Foo)
instance Eq Foo where
x == y = all id [ f x == f y
| f <- [field1, field2, field3] ]
instance Ord Foo where
compare x y = case (comparing field1) x y of
EQ -> case (comparing field2) x y of
EQ -> (comparing field3) x y
ord -> ord
ord -> ord
Maybe
和Either
等Monad对这类事情有一些非常好的支持,我发现自己希望Ordering
有类似的东西,例如。
instance Ord Foo where
compare == comparing field1 >>= comparing field2 >>= comparing field3
......或类似的东西。
我需要为复杂的数据类型执行此操作,其中无法对定义中的字段进行重新排序,并且取决于deriving (Eq, Ord)
的默认定义,因此我对解决方案不感兴趣该游戏的默认实例声明。
是否有更优雅,或至少更简洁的方式来定义这种排序?
谢谢!
答案 0 :(得分:17)
您可以将Monoid
实例用于Ordering
并在此处发挥良好作用:
instance Ord Foo where
compare = comparing field1 <> comparing field2 <> comparing field3
您可以使用的另一个技巧更容易概括为Eq
实例,是使用元组的实例:
equating = on (==)
reorder v = (field1 v, field2 v, field3 v)
instance Eq Foo where (==) = equating reorder
instance Ord Foo where compare = comparing reorder