One of the things I like about languages like Haskell and ML is how you can often figure out what a function does just by looking at its type. For example, I recently came across the on function (defined in Data.Function), which I had not encountered before. The example defines a function groupOn like so:
groupOn :: Eq b =>; (a ->; b) ->; [a] ->; [[a]]
groupOn f = groupBy ((==) `on` f)
and then shows how it can be used
groupOn isDigit "46a12b159c"
which yields
["46","a","12","b","159","c"]
So hmm, this on function seems pretty useful, but what does it do? To figure it out, just look at its type:
on :: (b ->; b ->; c) ->; (a ->; b) ->; a ->; a ->; c
That looks very similar to the type for function composition!
(.) :: (b ->; c) ->; (a ->; b) ->; a ->; c
From the types, it looks like on might work just like function composition, except that the first argument is a binary (rather than unary) function. It turns out that this is exactly what on does. Its definition is:
f `on` g = \x y ->; f (g x) (g y)
This simple function turns out to quite handy, especially if you favor a point-free style. Apparently the most common use for on is in conjuction with the various "By" functions in Data.List, where it is used to build predicates. For example:
sortBy (compare `on` fst) [(5,'a'),(1,'b'),(3,'c')] == [(1,'b'),(3,'c'),(5,'a')]
Useful stuff!
