[Haskell-cafe] (Feeling that) GHCi is trying to protect me from myself with overlapping instances and existential types

Juan Casanova juan.casanova at ed.ac.uk
Sun Feb 16 15:39:24 UTC 2020


Please keep the discussion coming. The fact that I'm not convinced  
(for now) doesn't mean I don't appreciate your answers. I wouldn't  
want to come out as hostile. I'd be very happy for you to convince me  
that I am understanding something the wrong way and learn how to do  
what I want in the right way, which is what has happened essentially  
every time I had a similar issue like this one. But until I am  
convinced please allow me to argue back.

> Didn't Arjen already provide such an example?  Should `g "Hello"`
> return a `Left` or a `Right`?
>
>   g :: String -> Either String String
>   g x = foo x
>

The g you are defining there should not compile indeed, because that  
is an ambiguous usage of foo. But that is not what I defined. And this  
relates to the rest of your reply.

> I think the difficulty may be due to the error being flagged in a
> misleading way.  There's nothing wrong with your intended usage of the
> type classes, individually.  The problem is that the instances both
> exist in the same codebase.  The error message about overlap *appears*
> at the use sites but I believe that this is an implementation detail.
>
> The instances you have written can cause problems in *other* parts of
> the codebase, perhaps completely unrelated parts that have merely
> transitively imported your module through dependencies (someone may
> define `g` above, for example).  Thefore the instances should not be
> both allowed to exist in the same codebase.  This particular piece of
> information is flagged at the use sites but perhaps should be flagged
> at the instance definition sites.

I simply do not agree with this, and I don't think (?) that GHCi  
implementors and designers agree with you either, as exemplified by  
the fact that indeed overlapping instances appear when using instances  
and not when defining them. While it doesn't clearly agree with what I  
said, the general phrasing and approach followed here:  
https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#instance-overlap makes me think indeed the approach is that potentially overlapping instances are allowed so long as each of their uses are  
unambiguous.

To address your point more specifically, you worry that if potentially  
overlapping instances exist, then someone somewhere else in the  
codebase might flag up the overlapping instances error. But in order  
for someone to do so, they need to *use* an instance of the class that  
has the potentially overlapping instances. In your example, they need  
to implement g and use foo within its definition, which means that  
they are willfully utilizing a Class1 instance that they are thinking  
of. If there are potentially overlapping instances that match, then  
they need to take care that they use the one they really want.

Now, it is true that a good argument is that, for example in the g  
example you presented, it is quite hard for the implementor to  
actually indicate which instance they wish to use, since in this case  
type annotations will not do the job. This is a problem I have also  
had to deal with myself, and generally solve on a case by case basis  
with various tricks and hacks (normally involving wrapping things in  
newtypes). In my application case for this problem we are discussing  
now, the newtype wrapping would in principle work, but would make my  
code extremely more complicated due to the amount of type classes that  
use each other that I am considering here and the fact that they are  
multi-parameter type classes. All in all I am not very happy anytime  
the solution to trying to do something legitimate is "wrap everything  
up in newtypes and coerce stuff all over the place until it works". I  
think it is too rampant and clutters the code way too much.

Perhaps the fact that no tools are given in GHCi to explicitly  
indicate which instance we wish to use is an argument in favour of  
your perspective that instances should not overlap even on their  
definition? Maybe someone reading this who's more closely situated to  
the Haskell / GHCi development and design principles could throw some  
light on this? I don't feel like it is made clear on any of the  
documentation I've read, but I may have overlooked it.

Rest assured, if it is like this by design as you claim it may be, I  
would have a big amount of complaints about that as well. Things that  
are absolutely sensible to do that would be made very noticeably  
harder to do by this design decision. But it would certainly address  
this particular issue.

Juan.


-- 
The University of Edinburgh is a charitable body, registered in
Scotland, with registration number SC005336.




More information about the Haskell-Cafe mailing list