词典Ord实例的优雅成语是什么?

时间:2018-02-11 02:41:16

标签: haskell lexicographic

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

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

背后的想法是,如果一件事在另一件事之前开始,你应该把它称为较小的,甚至不要看其他两个领域。同样地,如果它们同时开始但是一个更简短,那么简短的一个就是较小的,你可以忽略第三个字段。

3 个答案:

答案 0 :(得分:6)

使用deriving

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

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

答案 1 :(得分:4)

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

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

答案 2 :(得分:3)

As HTNW suggests,如果可以,请使用deriving。如果你不能(例如记录字段不是以适当的顺序,或者你实际上没有编写实例),一个非常好的选择就是compare(或{{3} },而不是(<=),而不是Monoid,然后利用Ordering的{​​{1}}实例,这相当于词典顺序:

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