Let\'s say that I have the following code:
import Data.List.Ordered
data Person = Person String String
deriving (Show, Eq)
main :: IO ()
main = print
You don't want to define multiple Ord
instances just to sort by different orders. You just need to use the sortBy
function, which takes an explicit comparison function as its argument.
Neat trick: if you use record types to define your Person
type, import Data.Function
(which gives you the on
function) and Data.Monoid
, you can use some neat tricks to make this much briefer and easy:
import Data.Function (on)
import Data.Monoid (mappend)
import Data.List (sortBy)
data Person = Person { firstName :: String, lastName :: String }
instance Show Person where
show p = firstName p ++ " " ++ lastName p
exampleData = [ Person "Mary" "Smith"
, Person "Joe" "Smith"
, Person "Anuq" "Katig"
, Person "Estanislao" "Martínez"
, Person "Barack" "Obama" ]
--
-- The "on" function allows you to construct comparison functions out of field
-- accessors:
--
-- compare `on` firstName :: Person -> Person -> Ordering
--
-- That expression evaluates to something equivalent to this:
--
-- (\x y -> compare (firstName x) (firstName y))
--
sortedByFirstName = sortBy (compare `on` firstName) exampleData
sortedByLastName = sortBy (compare `on` lastName) exampleData
--
-- The "mappend" function allows you to combine comparison functions into a
-- composite one. In this one, the comparison function sorts first by lastName,
-- then by firstName:
--
sortedByLastNameThenFirstName = sortBy lastNameFirstName exampleData
where lastNameFirstName =
(compare `on` lastName) `mappend` (compare `on` firstName)