"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

Reply via email to