The Haskell 2010 Language Report states in section 20.10.1.1 that:
deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]
In fact, the implementation in the GHC library would allow
deleteBy :: (b -> a -> Bool) -> b -> [a] -> [a]
but actually restricts the type to the former one with the annotation.
Hence, one cannot say, for instance:
foo = deleteBy fsteq 42 [(43, "foo"), (44, "bar"), (42, "baz")] where
fsteq a (b,_) = a == b
because Int
is not the same as (Int, String)
.
Is there any good reason for this?
The reason I am asking is that, if there is no good reason for it, I would include deleteBy
with the more general type in the Frege port of Data.List I am currently doing. But maybe I am overlooking something?
EDIT: As @hammar pointed out, this applies to other xxxBy functions also.
Generalising the type of
deleteBy
violates the standard in a very practical way: perfectly valid Haskell programs become invalid, thanks to unresolved overloading.Here's a demonstration:
In Haskell, this program is perfectly well-typed;
deleteBy
's restricted type ensures that the42
is guaranteed to have the same type as the1234
. With the generaliseddeleteBy
, this is not the case, and so the type of42
is ambiguous, making the program invalid. (If you want a less contrived example, consider a function which compares twoIntegral
values withtoInteger
.)So, perhaps there is no good reason for this restricted type (although if
deleteBy
is to be generalised, I would prefer hammar's version to your proposal), but generalising it does violate the standard, and it can break valid programs.