3

I have a very simple piece of code as follow:

{-# LANGUAGE
    MultiParamTypeClasses,
    FunctionalDependencies,
    FlexibleInstances,
    FlexibleContexts
#-}

class Graph g n e | g -> n e where
    nodes           :: g -> [n]                             
    edge            :: g -> (n,n) -> Maybe e                

instance Graph g Int e where
    nodes g = []
    edge g (n1,n2) = Nothing

I got an error related to the Coverage Condition fails for one of the functional dependencies. Do I need to add -XUndecidableInstances to permit this? or how I can fix this problem? Thanks

chipbk10
  • 5,783
  • 12
  • 49
  • 85
  • 5
    You functional dependency says that your choice of type `g` determines your node and element types `n` and `e`, respectively. Does it make sense, then, to say that all graph types `g` (knowing nothing about `g`) determine the node type to be `Int`? – sabauma Nov 24 '12 at 06:56
  • 1
    @sabauma, thanks! I never knew what the coverage condition is, but this little example showed me! :-) – luqui Nov 24 '12 at 11:30
  • @luqui Heh, I had never heard of the "coverage condition" before. I was only reasoning about the code. – sabauma Nov 24 '12 at 17:53
  • @sabauma: you should post your comments as an answer. – sclv Feb 01 '13 at 16:00

2 Answers2

5

The problem in your case is not Int but e. The Coverage Condition is documented in GHC's manual Sect. 7.6.3.2. Relaxed rules for instance contexts and says:

The Coverage Condition. For each functional dependency, tvsleft -> tvsright, of the class, every type variable in S(tvsright) must appear in S(tvsleft), where S is the substitution mapping each type variable in the class declaration to the corresponding type in the instance declaration.

What does it mean in practise? In your case, your functional dependency says g -> n e, which means that for each instance the types denoted by n and e are unique for the type denoted by g. Now let's say you're defining an instance

instance Graph SomeTypeG SomeTypeN SomeTypeE where
    ...

The coverage condition says that any type variable appearing in SomeTypeE or SomeTypeN must appear in SomeTypeG. What happens if it's not satisfied? Let's suppose a type variable a appears in SomeTypeE but not in SomeTypeG. Then for fixed SomeTypeG we would have an infinite number of possible instances by substituting different types for a.

In your case

instance Graph g Int e where
    ...

e is such a type variable, so by the Coverage Condition it must appear in g, which is not true. Because it doesn't appear there, your definition would imply that Graph g Int Int is an instances, Graph g Int (Maybe Char) is another instance, etc., contradicting the functional dependency that requires that there is precisely one.

If you had defined something like

instance Graph g Int Char where

then it would be OK, as there are no type variables in Int and Char. Another valid instance could be

instance Graph (g2 e) Int e where

where g2 is now of kind * -> *. In this case, e appears in g2 e, which satisfies the Coverage Condition, and indeed, e is always uniquely determined from g2 e.

Petr
  • 62,528
  • 13
  • 153
  • 317
1

Your functional dependency says that your choice of type g determines your node and element types n and e, respectively. Does it make sense, then, to say that all graph types g (knowing nothing about g) determine the node type to be Int?

sabauma
  • 4,243
  • 1
  • 23
  • 23