CMC*_*kai 1 sorting generics haskell
我试图实现一个排序的多属性排序,适用于任何事物的列表.
import Data.Ord (Ordering, Down (..), comparing)
import Data.List (sortBy)
import Data.Monoid (mconcat)
data Order a = ASC a | DESC a
orderBy :: Ord b => [Order (a -> b)] -> [a] -> [a]
orderBy rankedProperties unsorted =
sortBy rankedCompare unsorted
where
rankedCompare x y =
mconcat $ map
(\property ->
case property of
ASC f -> comparing f x y
DESC f -> comparing (Down . f) x y
) rankedProperties
Run Code Online (Sandbox Code Playgroud)
它现在适用于元组和记录,但是我发现了一个问题.问题是bin orderBy必须是相同的.这是考虑到这个:
data Row = Row { shortListed :: Bool, cost :: Float, distance1 :: Int, distance2 :: Int } deriving (Show, Eq)
Run Code Online (Sandbox Code Playgroud)
我希望能够说:orderBy [ASC shortListed, DESC cost] listofrows.
但是回来的错误是:
<interactive>:1:31:
Couldn't match type ‘Float’ with ‘Bool’
Expected type: Row -> Bool
Actual type: Row -> Float
In the first argument of ‘ASC’, namely ‘cost’
In the expression: ASC cost
Run Code Online (Sandbox Code Playgroud)
我需要一种方法来使b类型通用,因为b唯一真正必须被comparing函数接受comparing :: Ord a => (b -> a) -> b -> b -> Ordering.
我已经阅读了一些关于存在类型和异类列表的内容,但我不确定如何继续.
由于我们已经Monoid Ordering和instance Monoid b => Monoid (a -> b)in Prelude,我们也Monoid (a -> a -> Ordering)通过迭代函数实例两次.这让我们可以非常简单地解决问题,而不会存在:
import Data.Ord (Ordering, comparing)
import Data.List (sortBy)
import Data.Monoid ((<>), mconcat)
data Row = Row {
shortListed :: Bool,
cost :: Float,
distance1 :: Int,
distance2 :: Int
} deriving (Show, Eq)
asc, desc :: Ord b => (a -> b) -> a -> a -> Ordering
asc = comparing
desc = flip . asc
list :: [Row]
list = [Row False 0 10 20, Row True 10 30 40]
list' :: [Row]
list' = sortBy (asc shortListed <> desc cost <> asc distance1) list
Run Code Online (Sandbox Code Playgroud)
或者:
orderBy :: [a -> a -> Ordering] -> [a] -> [a]
orderBy = sortBy . mconcat
list'' :: [Row]
list'' = orderBy [asc shortListed, desc cost, asc distance1] list
Run Code Online (Sandbox Code Playgroud)