As an example, let's take the following algorithm for computing the longest common subsequence of two sequences, copied from Rosetta Code:
longest xs ys = if length xs > length ys then xs else ys
lcs [] _ = []
lcs _ [] = []
lcs (x:xs) (y:ys)
| x == y = x : lcs xs ys
| otherwise = longest (lcs (x:xs) ys) (lcs xs (y:ys))
lcs impicitly assumes that both arguments are of type Eq a => [a]; indeed, if I try to explicitly give the signature lcs :: [a] -> [a] -> [a] an error occurs on the line where x == y is, whereas the signature lcs :: Eq a => [a] -> [a] -> [a] works.
Now let's suppose I have two lists l1 and l2, both of type [(a,b)], and that I want the LCS between them, but in a way that uses the == operator in the definition of lcs only between the snds of each element (obviously b is required to belong to Eq typeclass).
I could provide lcs with not only the two lists, but also with the equality operator, which in the specific example above would be (==) `on` snd. The signature of lcs would then be (a -> a -> Bool) -> [a] -> [a] -> [a].
However, this would force the user to provide the equality operator even in the trivial case that one wants to use a plain (==), and wrapping the (a -> a) argument in a Maybe wouldn't help either.
In other words I feel that in the general case the constraint on the argument via Eq a => is ok, but in other cases one might want to pass a custom equality operator removing that constraint, which makes me thing of function overloading.
How should I go about this?
You simply provide both – a custom-operator version
lcsBy, and anEq a =>version which is implemented in terms of that.This is analogous to how the base library provides both
maximumandmaximumBy.