字典序 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
这段代码有效,但它很冗长,我相信还有更简洁的方法。
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)
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