Wish list: expanded defaulting, dependent types, reflection

Ashley Yakeley ashley@semantic.org
Sat, 29 Sep 2001 17:44:41 -0700


At 2001-09-29 17:07, Mike Gunter wrote:

>class Add a b c | a b -> c where add :: a -> b -> c
>instance Add Integer Integer Integer where add = (+)
>pt1 = (3::Integer) `add` (4::Integer)   -- Works fine,
>--ft2 = (5::Integer) `add` 6            -- Fails

OK, you're running across a fundamental design shortcoming in GHC's 
instance overlap calculation. What you want to do is this:

    class Add a b c | a b -> c where add :: a -> b -> c
    instance (Integral a,Integral b) => Add a b Integer where
        add a b = (toInteger a) + (toInteger b)
    pt1 = (3::Integer) `add` (4::Integer)
    ft2 = (5::Integer) `add` 6

So far so good. The trouble comes when you want to add your own type:

    instance (Integral b) => Add MyInt b MyInt where
        add (MkMyInt a) b = MkMyInt (a + (toInteger b))

Provided you don't declare 'instance Integral MyInt', the two instances 
will not de facto overlap. But GHC will complain that they do, because 
GHC's understanding of overlapping instances is excessively conservative. 
This is currently top of my list of GHC problems.

GHC annoyingly ignores the class contexts and simply sees this:

     Add a b _
     Add MyInt b _

...from which it deduces that the instances overlap.

So can't you just switch on -fallow-overlapping-instances and not worry 
about it? Ordinarily, yes, but for some reason that doesn't work when you 
have a dependent parameter in your class. It's like it's a different 
piece of code doing the checking, or something. I've entered a bug for 
this, see 
<http://sourceforge.net/tracker/?func=detail&aid=441389&group_id=8032&atid=
108032>. I don't know if this has been fixed in 5.02.

-- 
Ashley Yakeley, Seattle WA