Mike Gunter and Sigbjorn Finne propose generalising the type of the
*By functions as follows:
deleteBy :: (a -> Bool) -> [a] -> [a]
deleteFirstsBy :: (a -> b -> Bool) -> [a] -> [b] -> [a]
notElemBy,elemBy :: (a -> Bool) -> [a] -> [a] -- or just stick with any?
lookupBy :: (a -> Bool) -> [(a,b)] -> Maybe b
maximumBy, minimumBy :: (a -> a -> Bool) -> [a] -> a
nubBy :: (a -> a -> Bool) -> [a] -> [a]
elemIndexBy :: (a -> Bool) -> [a] -> Int
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
(the second arg. to List's deleteBy, elemBy, notElemBy, lookupBy and
elemIndexBy have been applied to the predicate here - I'm not fussed
either way).
I believe I'm to blame for proposing the *By functions - so I should
comment on this porposal.
My old argument against generalisation was that programmers would
benefit from having a simple rule that tells them how the name, type
signature and semantics of the overloaded function relates to the
non-overloaded function. Generalising the signature breaks this (eg
it doesn't make sense to require that a function of type (a -> b ->
Bool) be an equivalence.) Sigbjorn's partial application makes the
connection even more tenuous.
If we stop thinking of (most of) these functions as being
generalisations of Eq and Ord functions these problems go away. For
example, I've no objections to these signatures.
-- these don't directly generalise any Prelude functions
deleteFirst :: (a -> Bool) -> [a] -> [a]
deleteFirsts :: (a -> b -> Bool) -> [a] -> [b] -> [a]
find :: (a -> Bool) -> [(a,b)] -> Maybe b
indexOf :: (a -> Bool) -> [a] -> Int
-- these generalise Prelude functions
maximumBy, minimumBy :: (a -> a -> Bool) -> [a] -> a
nubBy :: (a -> a -> Bool) -> [a] -> [a]
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
(and remove elemBy, notElemBy and deleteBy)
There may be better names - the main point is that the "By" suffix
only gets used if we've replaced Eq/Ord in the context with (a -> a ->
Bool). We could also argue about whether indexOf should return "Maybe
Int".
Alastair Reid
Yale Haskell Project
ps
Sigbjorn also says:
The benefit of `elemBy' over `any' still eludes me though, anyone
care to enlighten me :-)
1) Consistency.
2) If you are trying to write a generalised version of some function
that you'd normally write using "elem", it may be clearer to use
"elemBy eq x ys" than to use "any (eq x) ys".