Consider the following Haskell code:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances,
FunctionalDependencies #-}
class C a b c | a b -> c
instance C (l (i,j)) (r i j) j
instance C (l i j) (r (i,j)) j
-- Conflict between the following two lines
instance C (l (i,j)) (r (i,j)) j
instance C (l i j) (r i j) j
Here, GHC yields a functional dependencies error between the last two lines. If I drop any of the last two instance declarations, the code compiles. I tried an analogue using type families, which also produced a conflict. My first question is: Why do the last two lines conflict, while the other declarations all work fine together?
In addition, if I change the very last line to
instance C (l i j) (r i j) i
GHC accepts the code. This seems quite weird, since the only thing that changes is the dependent type variable c. Can somebody explain this behavior?
The last two instances have a conflicting unification. Let me use completely different variable names:
C (a c (d,e)) (b c (d,e)) e
vs.
C (a c (d,e)) (b c (d,e)) (d,e)
In particular, your l
from the third instance can be unified with a type constructor which already has an argument applied.
Changing your j
to i
makes the last one instead:
C (a c (d,e)) (b c (d,e)) c
I still don't understand why that doesn't give a complaint. Perhaps it's because you can assign the types such that c = e
, but not such that e = (d,e)
(that would give an infinite type which Haskell doesn't allow), but it still seems like a dubious thing to allow. Perhaps this is even a GHC bug.
The other instance combinations don't conflict because when you try to unify them, you end up with contradictions similar to the e = (d,e)
above, but in the non-dependent parts, so they cannot match.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With