"S.D.Mechveliani" wrote:
> overlaps with the standard instance Eq a => Eq [a] ...
> and causes, in the existing implementations, many error reports -
> until the user satisfies everything by typing
>
> f :: (Eq a,Eq [a],Eq [[a]],Eq [[[a]]],Eq [[[[a]]]],
> Eq [[[[[a]]]]],Eq [[[[[[a]]]]]],Eq [[[[[[[a]]]]]]]
> )
> => Int -> a -> a -> Int
> f = ...
> And here, naturally, main = 93, unlike in the single instance case.
>
> As it was said, this is the simplest way to preserve the correct
> treating of overlapping instances.
> Note:
> * adding only Eq [[[[[[[a]]]]]]] would not suffice
> * if the extra instance shows n
> brackets, the forced type context has to contain about (n^2)/2
> of them.
> Such a program looks rather awkward.
Oddly enough, this sort of thing just hasn't come up when I use overlapping
instances ;-)
Yes, that's nicely pathological, but is it a real problem?
> ----------
> Also there is a curious point in the implementors terminology.
> They consider the contexts like
> (Eq a, Eq (a,a), Eq [a], Eq [[a]]) =>
>
> as normal and regular for the *user* program!
The above signature would only be necessary if you had overlapping instances
on pairs *and* on lists *and* on lists of lists *and* that the function in
question used equality on all of those types. That doesn't sound very normal
or regular ;-) But seriously, such a program, unless contrived, would be
fairly non-trivial. In that case, factoring all these things in, such a
context hardly seems such a problem, and I might even consider it good
documentation to the effect that there's a lot of overlapping going on here!
>
> And then, they discuss when and how such a context can be reduced by
> the compiler.
If such a context was necessary, because of overlapping instances, then the
context *would not* be reduced. That's the point. Overlapping instances can
prevent you from performing some context reductions.
>
> And according to the user's common sense, Eq a =>
> has to be considered as initial and regular, keeping in mind that
> there are *infinitely* many statements, like Eq [[a]], that can be
> derived logically and trivially from Eq a, according to the
> instances in scope.
But there can only be finitely many upon which you have an overlap. Saying
that `Eq a' is initial and regular is fine, but it implies that you are going
to derive all other necessary instances from it - which directly contradicts
having overlapping instances. You seem to want both.
>
> And then, the *implementor* (not the user) could think what the
> nasty reasons may force the compiler to extend explicitly the
> context with the deduced statements.
Let's take f again, as you've typed it:
f :: Eq a => a -> Bool
f x = Just x == Just x
Given an overlapping instance decl for Eq at type Maybe Bool (and the standard
instance Eq => Eq (Maybe a)), the compiler complains that you've left out `Eq
(Maybe a)' from the context. Why is this? Is it because the compiler can't
figure out how to derive `Eq (Maybe a)' from `Eq a'?
No. It is because it realizes that it *shouldn't* derive `Eq (Maybe a)' from
`Eq a', given the presence of the overlapping instance. Would it make sense
at this point for the compiler to say, "heck, I don't know why he put `Eq a'
in the context, what he really needs is `Eq (Maybe a)'", and just correct the
programmer's error for him? I'm afraid if you agree to that, then I'm afraid
you're also stuck with this:
f :: Eq a => a -> a -> Bool
f = (>)
What should the compiler do now? Should it say "heck, I don't know why he put
`Eq a' in the context, what he really needs is `Ord a'? In that case, the
context becomes meaningless in a signature.
--Jeff