A small oversight

I just discovered the highly useful function Data.Function.on. I vaguely recall a few people muttering a couple of years back that this would be a useful thing to have, but I had no idea it was in the standard libraries now. Anyway, while using it, I discovered a small omission from the Haskell libraries: We have min, max, minimum and maximum. We also have minimumBy and maximumBy. But there's no sign of minBy or maxBy. You can do, for example, (min `on` postcode) customer1 customer2 but that gives you the lowest postcode, not the customer to which this postcode belongs. By contrast, minimumBy (compare `on` postcode) [customer1, customer2] gives you the corresponding customer. But it seems silly to have to actually construct a list just for this. So... is there any danger of getting minBy and maxBy added? (I don't actually know off the top of my head where min and max are defined - the Prelude?) Also, constructions like sortBy (compare `on` foo) must surely be very common. Perhaps it would be an idea to define a family of functions like sortOn :: (Ord y) => (x -> y) -> [x] -> [x] sortOn foo = sortBy (compare `on` foo) Just an idea. Finally, take a look at this: newtype SwapOrd x = SwapOrd (unswap_ord :: x) deriving Eq instance Ord x => Ord (SwapOrd x) where compare x y = swap_ord $ compare x y swap_ord :: Ordering -> Ordering swap_ord o = case o of EQ -> EQ GT -> LT LT -> GT Just in case you wanted to sort things in reverse order. I think having swap_ord would be nice if nothing else...

Am Samstag, den 20.02.2010, 10:47 +0000 schrieb Andrew Coppin:
I just discovered the highly useful function Data.Function.on. I vaguely recall a few people muttering a couple of years back that this would be a useful thing to have, but I had no idea it was in the standard libraries now.
Anyway, while using it, I discovered a small omission from the Haskell libraries: We have min, max, minimum and maximum. We also have minimumBy and maximumBy. But there's no sign of minBy or maxBy. You can do, for example,
(min `on` postcode) customer1 customer2
but that gives you the lowest postcode, not the customer to which this postcode belongs. By contrast,
minimumBy (compare `on` postcode) [customer1, customer2]
gives you the corresponding customer. But it seems silly to have to actually construct a list just for this. So... is there any danger of getting minBy and maxBy added? (I don't actually know off the top of my head where min and max are defined - the Prelude?)
minBy and maxBy are already defined in Data.List - but they are local to minimumBy and maximumBy.

Also, constructions like
sortBy (compare `on` foo)
must surely be very common.
Just as a data point: I use constructions like the above very often. (Perhaps someone more enlightened than me can point out the connection to arrows?) Data.Function.on is surprisingly useful in some other contexts, too. Matthias.

I can't answer your question (about getting minBy into the libraries)
but I thought I'd point out some tricks:
On Sat, Feb 20, 2010 at 10:47 AM, Andrew Coppin
Also, constructions like
sortBy (compare `on` foo)
must surely be very common.
Common enough that Data.Ord introduces comparing: comparing :: (Ord a) => (b -> a) -> b -> b -> Ordering comparing = (compare `on`) see http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Ord.ht... But it would still be useful to have sortOn et al to capture the common technique when your sorting property is potentially expensive (sortOn length, for example): sortOn f = map fst . sortBy (comparing snd) . map (\x -> (x, f x)) a technique which I believe is called a Schwarzian transform.
Finally, take a look at this:
newtype SwapOrd x = SwapOrd (unswap_ord :: x) deriving Eq
instance Ord x => Ord (SwapOrd x) where compare x y = swap_ord $ compare x y
swap_ord :: Ordering -> Ordering swap_ord o = case o of EQ -> EQ GT -> LT LT -> GT
Just in case you wanted to sort things in reverse order. I think having swap_ord would be nice if nothing else...
swap_ord (compare x y) = compare y x, so usually flip compare fills this requirement :)

Ben Millwood wrote:
I can't answer your question (about getting minBy into the libraries) but I thought I'd point out some tricks:
On Sat, Feb 20, 2010 at 10:47 AM, Andrew Coppin
wrote: Also, constructions like
sortBy (compare `on` foo)
must surely be very common.
Common enough that Data.Ord introduces comparing:
comparing :: (Ord a) => (b -> a) -> b -> b -> Ordering comparing = (compare `on`)
Heh. I didn't even notice that Data.Ord existed...
But it would still be useful to have sortOn et al to capture the common technique when your sorting property is potentially expensive (sortOn length, for example):
sortOn f = map fst . sortBy (comparing snd) . map (\x -> (x, f x))
a technique which I believe is called a Schwarzian transform.
Yes, that looks quite useful...
swap_ord (compare x y) = compare y x, so usually flip compare fills this requirement :)
*facepalm* Damnit, why didn't *I* think of that??

On Sat, Feb 20, 2010 at 5:47 AM, Andrew Coppin
sortOn :: (Ord y) => (x -> y) -> [x] -> [x] sortOn foo = sortBy (compare `on` foo)
Incidentally, this function is provided as Data.List.Ordered.sortOn'
in the data-ordlist package...
On Sat, Feb 20, 2010 at 7:39 AM, Ben Millwood
But it would still be useful to have sortOn et al to capture the common technique when your sorting property is potentially expensive (sortOn length, for example):
sortOn f = map fst . sortBy (comparing snd) . map (\x -> (x, f x))
a technique which I believe is called a Schwar[t]zian transform.
An older name for this technique is "decorate-sort-undecorate". Data-ordlist also provides this as Data.List.Ordered.sortOn http://hackage.haskell.org/package/data-ordlist Best, Leon

On Sun, 21 Feb 2010, Leon Smith wrote:
On Sat, Feb 20, 2010 at 5:47 AM, Andrew Coppin
wrote: sortOn :: (Ord y) => (x -> y) -> [x] -> [x] sortOn foo = sortBy (compare `on` foo)
Incidentally, this function is provided as Data.List.Ordered.sortOn' in the data-ordlist package...
Or Key.sort in utility-ht which caches the keys to be sorted. Useful if the function is not just a record selector. http://hackage.haskell.org/packages/archive/utility-ht/0.0.5.1/doc/html/Data...
participants (7)
-
Andrew Coppin
-
Ben Millwood
-
Daniel Fischer
-
Henning Thielemann
-
Holger Siegel
-
Leon Smith
-
Matthias Görgens