# Proposal #2659: Add sortOn and friends to Data.List

Twan van Laarhoven twanvl at gmail.com
Sun Oct 5 11:39:40 EDT 2008

```Hello list,

Almost all uses of sortBy in user code use 'comparing', 'on' or a similar
construction . I think we should add a function that makes this common
behavior more convenient:

sortOn :: Ord b => (a -> b) -> [a] -> [a]

For consistency we should also add *On for the other *By functions in Data.List:

nubOn           :: Eq b => (a -> b) -> [a] -> [a]
deleteOn        :: Eq b => (a -> b) -> a -> [a] -> [a]
deleteFirstsOn  :: Eq b => (a -> b) -> [a] -> [a] -> [a]
unionOn         :: Eq b => (a -> b) -> [a] -> [a] -> [a]
intersectOn     :: Eq b => (a -> b) -> [a] -> [a] -> [a]
groupOn         :: Eq b => (a -> b) -> [a] -> [[a]]
sortOn          :: Ord b => (a -> b) -> [a] -> [a]
insertOn        :: Ord b => (a -> b) -> a -> [a] -> [a]
maximumOn       :: Ord b => (a -> b) -> [a] -> a
minimumOn       :: Ord b => (a -> b) -> [a] -> a
(nubSortOn       :: Ord b => (a -> b) -> [a] -> [a]) -- see #2629

-- Naming --

"On": The reason for the "on" suffix is that it relates to the "on" function
from Data.Function: "sortOn f = sort (compare `on` f)". In code, "sortOn fst" is
reasonably natural, "sortBy fst" would be better but that is already taken.

"With": Another possible choice is the "with" suffix. There is some precedence
for this choice . A big disadvantage is that the "with" suffix is commonly
used for combining functions, as in Data.Map.unionWith. Making a
Data.List.unionWith that does something completely different sounds like a bad idea.

"ByComparing": Defining
sortByComparing f = sortBy (comparing f)
makes sense, naming wise. A disadvantage of this name is that it is too long.
Also, we would get a distinction between "groupByEquating" and "sortByComparing".

-- Variations --

When f is a slow function the call "sortOn f xs" recomputes f more than
necessary. A version that caches the result of f is easy to define:

sortOn' f = map fst . sortOn snd . map (\x -> (x,f x))

This is perhaps not the best name, since ' usually means strictness.

-- Descending sort--

To be able to sort lists in reverse order, a simple newtype should be added to
Data.Ord:

newtype Down a = Down { getDown :: a }

instance Ord a => Ord (Down a) where
Down x < Down y  =  y < x

Now "sortOn Down xs == reverse (sort xs)".
The name Down comes from , maybe Desc is a better name?

-- Proposal--

Ticket:   #2659 (for sortOn and friends)
Ticket:   #2660 (for Down newtype)

Questions:
1. should sortOn be added to Data.List?
2. should all other *On functions be added as well?
3. what name should these functions get?
5. should Down be added to Data.Ord?

Note: The addition of sortOn was previously proposed as #2406 and rejected
because it did not follow the library submission guidelines.

Twan