36

我想先按一个属性排序,然后再按另一个(如果第一个属性相同。)

Haskell 中组合两个比较函数的惯用方式是什么,即使用 with 的函数sortBy

给定

f :: Ord a => a -> a -> Ordering
g :: Ord a => a -> a -> Ordering

组成f并将g产生:

h x y = case v of
          EQ -> g x y
          otherwise -> v
        where v = f x y
4

2 回答 2

54

vitus 指出了 for 的一个非常酷的Monoid例子Ordering。如果你将它与实例结合起来,instance Monoid b => Monoid (a -> b)你的组合函数只是(准备好):

mappend

看看这个:

Prelude Data.Monoid> let f a b = EQ
Prelude Data.Monoid> let g a b = LT
Prelude Data.Monoid> :t f `mappend` g
f `mappend` g :: t -> t1 -> Ordering
Prelude Data.Monoid> (f `mappend` g) undefined undefined 
LT
Prelude Data.Monoid> let f a b = GT
Prelude Data.Monoid> (f `mappend` g) undefined undefined 
GT

+1 用于强大而简单的抽象

于 2012-07-14T19:16:39.333 回答
3

您可以使用<>运算符。在此示例bigSort中,按字符串的数值对字符串进行排序,首先比较长度,然后按字典顺序进行比较。

import Data.List (sortBy)
import Data.Ord (compare, comparing)

bigSort :: [String] -> [String]
bigSort = sortBy $ (comparing length) <> compare

例子:

bigSort ["31415926535897932384626433832795","1","3","10","3","5"] = 
        ["1","3","3","5","10","31415926535897932384626433832795"]

<>mappend来自Data.Monoid module(参见jberryman答案)的别名。

(免费)书Learn You a Haskell for Great Good!在第 11 章中解释了它是如何工作的

instance Monoid Ordering where  
   mempty = EQ  
   LT `mappend` _ = LT
   EQ `mappend` y = y
   GT `mappend` _ = GT

实例是这样设置的:当我们mappend有两个Ordering值时,左边的那个被保留,除非左边的值为EQ,在这种情况下,右边的就是结果。身份是EQ

于 2020-03-12T15:17:07.943 回答