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




Reply via email to