## 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.

Thursday, 24th May, 2012 at 3:59 pm

Good explanation. I think the definition of “comparing” is easier to understand, but the function “on” is more general and powerful. You could even implement “comparing” in terms of “on”:

comparing f = compare `on` f

Thursday, 24th May, 2012 at 9:16 pm

Dear Gregory

Thank you for your comment.

I agree that on is more general and powerful. I think I’d like to see more concrete examples of it in use.

(three years on, I’m still only an occasional dabbler in Haskell.)

Thursday, 24th May, 2012 at 9:24 pm

Yeah, I also tried to think of an example of ‘on’ outside of ‘compare’. Here’s what I came up with:

> :type (zip `on` words)

(zip `on` words) :: String -> String -> [(String, String)]

> (zip `on` words) “hello, world!” “goodbye, sam!”

[(“hello,”,”goodbye,”),(“world!”,”sam!”)]

So it’s a kind of transpose operator for text. Kind of contrived, but it works!

Sunday, 27th May, 2012 at 8:22 am

Nice! I’ll try and think of something too.