字典序 Ord 实例的优雅习语是什么?

What is an elegant idiom for a lexicographic Ord instance?

这段代码有效,但它很冗长,我相信还有更简洁的方法。

import qualified Data.Vector as V

data Event a = Event { start :: Time
                     , duration :: Time
                     , payload :: Maybe a } deriving (Show, Eq)

instance Ord a => Ord (Event a) where
  (<=) a b = start a < start b
    || start a == start b && duration a < duration b
    || start a == start b && duration a == duration b && payload a <= payload b

其背后的想法是,如果一件事先于另一件事,则应称其为较小的,而不要看其他两个领域。同理,如果同时开始,但有一个更简短,则那个更简短的那个更短,可以忽略第三个字段。

使用deriving:

data Event a = Event { start :: Time
                     , duration :: Time
                     , payload :: Maybe a } deriving (Show, Eq, Ord)

派生实例自动按字典顺序排列。

正如@HTNW 指出的那样,自动派生的 Ord 实例将起作用。在更一般的情况下,如果您需要按字典顺序对多个项目进行排序,每个项目都有现有的 Ord 个实例,您可以使用自动元组 Ord instance:

instance Ord a => Ord (Event a) where
  (<=) a b = order a <= order b
    where order x = (start x, duration x, payload x)

, use deriving if you can. If you can't (e.g. the record fields aren't in the appropriate order, or you aren't actually writing an instance), a very nice option is doing it in terms of compare (or comparing,这在你的情况下增加了额外的便利)而不是 (<=) 然后利用 Monoid 实例 Ordering,这相当于字典顺序:

import Data.Ord (comparing)
import Data.Monoid ((<>))

instance Ord a => Ord (Event a) where
    compare a b = comparing start a b
        <> comparing duration a b
        <> comparing payload a b

由于函数有一个作用于结果的 Monoid 实例,您可以更进一步:

instance Ord a => Ord (Event a) where
    compare = comparing start <> comparing duration <> comparing payload