为 s 列表创建一个全新的Ord
实例对Int
我来说似乎有点重量级(更不用说您可能会造成混乱:稍后出现您的代码的人可能会期望默认的、未分级的词典比较行为)。
如果您只是希望不必在每次使用时都复制自定义比较代码sortBy
等,那么实际上有一种相当轻量级的方法可以在现场定义像您这样的链式比较函数。Ordering
碰巧是 的一个实例Monoid
,这意味着您可以根据一系列标准比较两个事物,然后使用函数(最近缩写为)组合Ordering
这些比较的结果。这一切都在Learn You a Haskell 关于 Monoids 等的章节中进行了详细解释,这就是我学习技巧的地方。所以:Monoid
mappend
<>
import Data.Monoid ((<>))
import Data.Ord (comparing)
gradedLexicographicCompare :: (Ord a) => [a] -> [a] -> Ordering
gradedLexicographicCompare xs ys = comparing length xs ys <> comparing id xs ys
(当然comparing id
is just compare
,但为了统一起见......)然后写这样的东西就变得相对轻松了
f = ... sortBy s ...
where
...
s xs ys = comparing length xs ys <> compare xs ys
...
这也具有您的继任者会立即看到您正在使用自定义比较功能的优点。
更新:leftaroundabout 在下面指出,我们可以实现更高的优雅——毕竟这是 Haskell,在 Haskell 中,我们总是可以实现更高的优雅——通过使用 monoid 实例,instance Monoid b => Monoid (a -> b)
. 也就是说,结果是幺半群的函数本身可以被认为是一个幺半群。该实例由
instance Monoid b => Monoid (a -> b) where
mempty _ = mempty
mappend f g x = f x `mappend` g x (1)
现在让我们沉迷于一点等式推理,看看comparing length <> compare
根据这个例子扩展了什么。应用(1)一次,我们有
comparing length <> compare
= mappend (comparing length) compare
= \xs -> mappend ((comparing length) xs) (compare xs) (2)
但是((comparing length) xs) :: [a] -> Ordering
和(compare xs) :: (Ord a) => a -> Ordering
本身是函数,其结果是幺半群,即Ordering
s,所以我们可以再次应用 (1) 以获得
mappend ((comparing length) xs) (compare xs)
= \ys -> mappend (((comparing length) xs) ys) ((compare xs) ys) (3)
但现在(((comparing length) xs) ys)
和((compare xs) ys)
都是完全应用的功能。具体来说,它们是Ordering
s,从原始答案中我们知道如何使用的实例组合两个Ordering
s 。(请注意,我们没有使用from (1)。)将所有内容写在一个大链中,我们有mappend
Ordering
Monoid
mappend
comparing length <> compare
= mappend (comparing length) compare [definition of <>]
= \xs -> mappend ((comparing length) xs) (compare xs) [by (1)]
= \xs -> (\ys -> mappend (((comparing length) xs) ys) ((compare xs) ys)) [substituting (3) in (2)]
= \xs -> \ys -> mappend (comparing length xs ys) (compare xs ys) [function application is left associative]
= \xs -> \ys -> comparing length xs ys <> compare xs ys [definition of <>]
而这个扩展的最后一行只是我们原来的gradedLexicographicCompare
!经过漫长的题外话,妙语是我们可以写出优雅的无分
gradedLexicographicCompare = comparing length <> compare
漂亮的。