A nice way of sorting
15 Jan 2022This blog post is to explore a really clean way of sorting a list in Haskell.
Suppose you have a type such as
data Person = Person
{ name :: String
, age :: Int
}
And you want to sort first by age, from older to younger, and then by name. A naive approach would be something like
comparePerson :: Person -> Person -> Ordering
comparePerson (Person name1 age1) (Person name2 age2)
| age1 > age2 = LT
| age1 < age2 = GT
| name1 > name2 = GT
| name1 < name2 = LT
| otherwise = EQ
And it pretty much works
lst = [ Person "A" 10
, Person "B" 20
, Person "B" 5
, Person "C" 10
]
sorted = sortBy comparePerson lst
-- Which is [ Person "B" 20
-- , Person "A" 10
-- , Person "C" 10
-- , Person "B" 5
-- ]
But the function is ugly, and quite error prone to write.
Enters the semigroup instance of Ordering
, which is defined as
instance Semigroup Ordering where
LT <> _ = LT
EQ <> y = y
GT <> _ = GT
We can then use comparing
from Data.Ord
with a couple of aliases and sort our list with
code that is simpler and clearer.
asc f = comparing f
desc f = flip (comparing f)
sorted = sortBy (desc age <> asc name) lst
Isn't that neat?