decorate-sort-undecorate in Haskell — Advanced!
Saturday, 11th July, 2009
Last in the (unplanned!) series on decorate-sort-undecorate in Haskell, this post reports on the Further Work necessary after the reponses to my initial query on haskell-beginners.
I received many helpful responses, many of which used Haskell language features which were new to me. Here I summarise them and then give a description of the new elements.
Haskell: sortBy wrapped_f, sortBy (comparing f), and sortBy (compare `on` f)
Sunday, 28th June, 2009
Here are three version of sortByLength:
import Data.List -- [1] longer :: [a] -> [a] -> Ordering longer a b = compare (length a) (length b) sortByLength0 :: [[a]] -> [[a]] sortByLength0 a = sortBy longer a -- [2] import Data.Ord sortByLength1 = sortBy (comparing length) -- [3] import Data.Function sortByLength = sortBy (compare `on` length)
As discussed in my previous post, the first was my answer to the exercise in Real World Haskell, the second is from comment 5 by Yair, the third is based on comment 8 by David. Thank you Yair and David for these suggestions.
The three versions are equivalent (although I admit I haven’t tested them for speed). With particular relevance to my previous post, none of these use decorate-sort-undecorate. [2] and [3] are clearly better than [1] as they obviate the need for the wrapper function longer. [2] is my favourite for its readability.
Another thing worth noting is that [2] and [3] omit the parameter a from the definition.
comparing and `on` are new to me, so I’ll outline them briefly here.
comparing
comparing is in Data.Ord:
comparing :: Ord a => (b -> a) -> b -> b -> Ordering comparing p x y = compare (p x) (p y)
So longer a b is equivalent to comparing length a b.
`on`
Using backticks around a function allows us to use the function as an infix rather than a prefix (see rwh ch 4, section Infix functions p 76), so the following are exactly equivalent:
(compare `on` length) (on compare length)
on is from Data.Function:
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c (*) `on` f = \x y -> f x * f y
I can understand the type signature, and I can see how on compare length a b would fit, but I’m afraid the definition is opaque. I might be able to come back to it after I’ve written about ., $ and &&&. Otherwise, I shall spend some time with my eyes open for different usages of on in the wild. It was very difficult finding information on on (many thanks to a contact on haskell-beginners who pointed me to Hoogle), so I think it will be worth writing up when I can.
Discussion
It took the omission of parameters from [2] and [3] for me to realise that perhaps the thing about Haskell is how much it facilitates combining and mixing functions in different ways. Duh.