As you have specified it, the OrdByKey class can only have one instance
per type, when it sounds like you would like to be able to declare an instance
for each field in your record type.
To accomplish that, you will have to put the field type into the class
definition as well. This lets you do something like the following:
{-# LANGUAGE MultiParamTypeClasses #-}
data Person = Person { name :: String, age :: Int }
class (Ord r) => OrdByKey o r where
orderKey :: o -> r
instance OrdByKey Person Int where
orderKey p = age p
x <=? y = (orderKey x :: Int) <= (orderKey y :: Int)
However, you can only have one instance per field type, so if your
Person type looks like
data Person = Person { name :: String, age :: Int, ssn :: String}
you will not be able to have a version to compare on both the name and
the ssn fields. You could get around this by wrapping each field in a
newtype so each field has a unique type. So your Person type would look
like
data Person = Person { name :: Name, age :: Age, ssn :: SSN}
That would lead to a lot of newtypes floating around though.
The real downside of this is the need to specify the return type for the
orderKey function. I would recommend using the on function from
Data.Function to write the appropriate comparison functions. I think a
function like
compareByKey :: (Ord b) => (a -> b) -> a -> a -> Bool
compareByKey = on (<=)
generalizes your idea of "can be compared by some key". You just have to give
it the function that extracts that key, which would be exactly the accessor
functions for your Person type, in this case.
I can't think of an instance where the OrdByKey class would be useful and trying to overload the <= with multiple versions for the same type seems like it would be down right
confusing in practice.
OrdforPersonto compare that particular field. - sabaumacomparing age you me- Michael Steelecomparingyou could take a look aton. It has type(b -> b -> c) -> (a -> b) -> a -> a -> c, socomparing age = on compare agebut you could also makeon (==) fto test two things for equality after applyingf. - Laar