2014-04-06 34 views
6

說我有一個像數據類型如下:寫對多個屬性排序比較優雅的方式

data Foo = Foo { field1, field2, field3 :: Int } 

而且我想通過比較field1field2,並field3使它的Ord一個實例一個特定的順序。

我覺得很討厭寫:

-- (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 

單子像MaybeEither有這種事情一些非常不錯的支持,我發現自己希望的是Ordering有類似的東西,例如

instance Ord Foo where 
    compare == comparing field1 >>= comparing field2 >>= comparing field3 

...或類似的東西。

我需要爲複雜數據類型執行此操作,其中對定義中的字段進行重新排序並取決於deriving (Eq, Ord)的默認定義是不可能的,所以我對遊戲默認實例聲明的解決方案不感興趣。

是否有更優雅或至少更簡潔的方式來定義這種排序?

謝謝!

+2

這裏是一個無關的提示:'所有ID'和'和:: [Bool] - > Bool'一樣 – cdk

回答

13

可以使用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 
+0

美麗。謝謝! – koschei