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?
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With