Help interpret overlapping error message instances

I came across this overlapping instance error message. Sorry, this is not a trivial project, but the error should be local to type signatures.

First I declare f a specific type,

let f = undefined :: (CompNode Int) 

Then I try to call my function pshow :: PrettyShow a => a -> String . I am getting this error message.

 > pshow f <interactive>:1:1: Overlapping instances for PrettyShow (CompNode Int) arising from a use of `pshow' Matching instances: instance (G.Graph g, PrettyShow (G.Vertex g)) => PrettyShow g -- Defined at Graph.hs:61:10-57 instance (PrettyShow a, Show a) => PrettyShow (CompNode a) -- Defined at Interpreter.hs:61:10-58 

The problem is that CompNode Int not a graph, so I don’t think the first matching instance should start. (The second is the one I want to execute.) Indeed, if I write a function that requires its argument to be a graph,

 > :{ | let g :: G.Graph a => a -> a | g = id | :} 

and then call it f, I get the expected instance error message,

 > gf <interactive>:1:1: No instance for (G.Graph (CompNode Int)) 

Thank you in advance, sorry. I am using GHC 7.0.4.

+4
source share
1 answer

The problem is that CompNode Int is not a graph, so I don't think that the first matching instance should start.

You would think so, but, unfortunately, this does not work.

When the GHC selects an instance, it looks only at the head, i.e. to the part after the class name. Only after selecting an instance does it check the context, i.e. Part before => . Inconsistencies in the context can cause the instance to be rejected and result in type checking errors, but they will not lead to the GHC failing and looking for another instance.

So, given these instances:

 instance (G.Graph g, PrettyShow (G.Vertex g)) => PrettyShow g instance (PrettyShow a, Show a) => PrettyShow (CompNode a) 

... if we ignore the context, they look like this:

 instance PrettyShow g instance PrettyShow (CompNode a) 

What should make it clear that the first instance is completely common and covers absolutely everything.

In some cases, you can use the OverlappingInstances extension, but this will not change the behavior above; rather, it allows the GHC to resolve ambiguous instances, choosing uniquely the most specific, if any. But using matching instances can be tricky and lead to cryptic errors, so I would advise you to rethink the design first and see if you can completely fix the problem.

However, in the specific example here, CompNode a indeed a uniquely more specific match for CompNode Int , so the GHC will select it instead of the generic instance.

+4
source

All Articles