组成两个比较函数?

时间:2012-07-14 18:48:27

标签: sorting haskell

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

Haskell中组成两个比较函数的惯用方法是什么,即与sortBy一起使用的函数?

鉴于

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

撰写fg会产生:

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

2 个答案:

答案 0 :(得分:51)

vitus为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用于强大而简单的抽象

答案 1 :(得分: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"]

<>mappendData.Monoid module的别名(请参见 jberryman 答案)。

(免费)这本书学到一个Haskell来造福大人!Chapter 11

中解释了它的工作原理。
instance Monoid Ordering where  
   mempty = EQ  
   LT `mappend` _ = LT
   EQ `mappend` y = y
   GT `mappend` _ = GT

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