【问题标题】:What is an elegant idiom for a lexicographic Ord instance?字典式 Ord 实例的优雅习语是什么?
【发布时间】:2018-02-11 02:41:15
【问题描述】:

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

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

其背后的想法是,如果一件事先于另一件事开始,则应将其称为较小的,甚至不要看其他两个领域。类似地,如果它们同时开始,但其中一个更简短,那么那个更简短的那个就更少,您可以忽略第三个字段。

【问题讨论】:

    标签: haskell lexicographic


    【解决方案1】:

    使用deriving:

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

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

    【讨论】:

      【解决方案2】:

      正如@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)
      

      【讨论】:

      • 如果要保存击键,可以使用Data.Function.on:(&lt;=) = (&lt;=) `on` order。你也可以把它做成一个(嗯,两个)-liner:(&lt;=) = on (&lt;=) $ (,,) &lt;$&gt; start &lt;*&gt; duration &lt;*&gt; payload
      【解决方案3】:

      As HTNW suggests,如果可以,请使用deriving。如果你不能(例如,记录字段的顺序不正确,或者你实际上并没有编写实例),一个非常好的选择是使用compare(或comparing,它添加在您的情况下更方便)而不是(&lt;=),然后利用OrderingMonoid 实例,这相当于字典顺序:

      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
      

      【讨论】:

      • 不错。现在我因为一周前写了applyCmp f x y = mconcat (f &lt;*&gt; pure x &lt;*&gt; pure y)而感到愚蠢。
      猜你喜欢
      • 2014-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-04
      • 1970-01-01
      • 1970-01-01
      • 2019-09-28
      • 2011-07-20
      相关资源
      最近更新 更多