Let's say we have a custom data type:
data Person = Person { first_name :: String,
last_name :: String,
age :: Int
} deriving (Ord, Eq, Show)
Let's also say I have a list of these Person data types. I've already made a function that sorts these Persons in order, but this is limited to the first value of each person, first_name. What I'm trying to do is modify the Person data type so that this sort function sorts by the age instead of first_name (besides just swapping the value order so that age is first). I know I need to use the instance keyword to write my own compare function for Ord. This is where I'm stuck. Can anyone help me out?
Edit: Yep, this is HW-- I unfortunately need to do it the way I'm describing.
The easiest and most flexible way to deal with that problem, given that there are multiple valid ways to sort Person
values, is not by changing the Ord
instance, but by using a custom sorting function.
import Data.List (sortBy)
import Data.Ord (comparing)
sortByAge :: [Person] -> [Person]
sortByAge = sortBy (comparing age)
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
makes a custom sorting function from a comparison function, while comparing :: Ord a => (b -> a) -> b -> b -> Ordering
makes such a comparison function given, for instance, a field acessor. Be sure to have a good look at the involved type signatures in order to grok how everything fits together.
If you do need to change the Ord
instance, here is how it would go. The syntax is as follows:
instance Ord Person where
compare = undefined -- placeholder
The documentation tells us that, from all of the Ord
methods, we just need to implement compare
. Now, what should we replace undefined
with? We want the comparison to be based on age
, which is an Int
field. Since Int
is an instance of Ord
, the answer is immediate:
instance Ord Person where
compare x y = compare (age x) (age y)
Incidentally, the definition of comparing
is:
comparing :: (Ord a) => (b -> a) -> b -> b -> Ordering
comparing p x y = compare (p x) (p y)
And so we could write the instance in the style we used for the first solution:
instance Ord Person where
compare = comparing age
Remove Ord
from the list of derived type classes, if you have to write your own instance, the compiler generated one will clash. Also, this is not idiomatic, and I don't recommend this in general.
You can write the Ord instance yourself now the usual way:
instance Ord Person where
compare b1 b2 = ...
I'll let you fill in the details as a useful exercise. Once that's done, the normal sort function will do what you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With