Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Haskell's Data.List.deleteBy takes in input a comparison function (a -> a -> Bool) and a value instead of a predicate (a -> Bool)?

Tags:

haskell

I have a question related to Data.List and the signature of deleteBy. Ideally this function should take in input a predicate and delete the first element for which the predicate is true. Something like:

deleteBy :: (a -> Bool) -> [a] -> [a]
deleteBy p = go
    where go []                   = []
          go (x:xs) | p x         = xs
                    | otherwise   = x:go xs

Instead the function defined in the library takes both a predicate and a value:

deleteBy                :: (a -> a -> Bool) -> a -> [a] -> [a]
deleteBy _  _ []        = []
deleteBy eq x (y:ys)    = if x `eq` y then ys else y : deleteBy eq x ys

It's easy to see that eq is always used with x as first argument and x is fixed in deleteBy, so there is no reason to get both eq and x instead of eq x. On contrary, by taking a predicate working on a single element you can pass predicates that don't compare two values, such as a function that works on a part of the type a or a trivial function like cons true. My question is: why deleteBy has been implemented in this way?

like image 760
mariop Avatar asked Apr 10 '14 23:04

mariop


1 Answers

The deleteBy function is a generalization of delete, so it's helpful to take a look at delete first.

delete :: Eq a => a -> [a] -> [a]

delete takes a value Eq a => a, then deletes the first occurance of that value from the [a] using the (==) from the Eq instance.

As with all the *By functions in Data.List, the Eq constraint is removed and the programmer is required to provide their own replacement (==) function.

So removing the Eq constraint from delete and replacing it with the type of (==), namely a -> a -> Bool, gives you the type of deleteBy.

In other words, it's for consistency with the rest of the *By operations in Data.List.

like image 94
cdk Avatar answered Oct 14 '22 03:10

cdk