Overlapping (etc) instances
This self-contained module:
{-# LANGUAGE FlexibleInstances, OverlappingInstances, UndecidableInstances #-}
module Foo where
class Sat a
class Data ctx a
instance Sat (ctx Char) => Data ctx Char
instance (Sat (ctx [a]), Data ctx a) => Data ctx [a]
class Data FooD a => Foo a
data FooD a = FooD
instance Foo t => Sat (FooD t)
instance Data FooD a => Foo a
instance Foo a => Foo [a]
instance Foo [Char]
gives this error in the HEAD (and a similar, but less helpful, error in 6.6):
$ ghc -c Foo.hs
Foo.hs:18:0:
Overlapping instances for Foo [a]
arising from the superclasses of an instance declaration
at Foo.hs:18:0
Matching instances:
instance [overlap ok] (Foo a) => Foo [a]
-- Defined at Foo.hs:18:0-30
instance [overlap ok] Foo [Char] -- Defined at Foo.hs:19:0-33
(The choice depends on the instantiation of `a'
Use -fallow-incoherent-instances to use the first choice above)
In the instance declaration for `Foo [a]'
Simon writes:
The reason is this:
In the instance for Foo [a]
we need a superclass (Data FooD [a])
using the instance for Data, we therefore need
(Sat (FooD [a], Data FooD a)
But we are given Foo a, and hence its superclass Data FooD a
So that leaves (Sat (FooD [a]))
Using the instance for Sat means
we need (Foo [a])
At that point GHC says there are two instances that match Foo [a], and which one
to choose depends on how you instantiate a.
What we wanted was to "tie the knot" and use Foo [a] recursively, the very one
we are constructing. GHC does that when solving Foo [a], but not when
constructing it.
This is a good point, I will think about it. It's a bit delicate. Meanwhile,
can you Trac it? It's a nice example.
A larger module showing how the instances above can be desirable in a real program is this (requires the syb-with-class package from hackage):
{-# LANGUAGE TemplateHaskell, FlexibleInstances, CPP,
OverlappingInstances, UndecidableInstances #-}
module Main where
import Data.Generics.SYB.WithClass.Basics
import Data.Generics.SYB.WithClass.Instances ()
data Element = Elem String [Element]
| CData String
deriving Show
class Data XmlD a => Xml a where
toXml :: a -> [Element]
toXml = defaultToXml
data XmlD a = XmlD { toXmlD :: a -> [Element] }
xmlProxy :: Proxy XmlD
xmlProxy = error "xmlProxy"
instance Xml t => Sat (XmlD t) where
dict = XmlD { toXmlD = toXml }
defaultToXml :: Xml t => t -> [Element]
defaultToXml x = [Elem (constring $ toConstr xmlProxy x)
(concat $ gmapQ xmlProxy (toXmlD dict) x)]
-----
instance Data XmlD t => Xml t
#ifdef STRING
instance Xml String where
toXml x = [Elem "string" [CData x]]
#endif
#ifdef LIST
instance Xml a => Xml [a] where
toXml = concatMap toXml
#endif
main :: IO ()
main = do print $ toXml (Just True)
print $ toXml [True, False]
print $ toXml "foo"
which allows us to specialise XML marshalling for either lists (ignoring all the (:) and [] constructors) or strings (turn them into CData), but not both:
$ ghci -v0 -DLIST z.hs
*Main> main
[Elem "Just" [Elem "True" []]]
[Elem "True" [],Elem "False" []]
[Elem "f" [],Elem "o" [],Elem "o" []]
*Main>
$ ghci -v0 -DSTRING z.hs
*Main> main
[Elem "Just" [Elem "True" []]]
[Elem "(:)" [Elem "True" [],Elem "(:)" [Elem "False" [],Elem "[]" []]]]
[Elem "string" [CData "foo"]]
*Main>
$ ghci -v0 -DLIST -DSTRING z.hs
[overlapping instances error]
If we replace the
instance Xml a => Xml [a] where
line with
instance (Xml a, Xml [a]) => Xml [a] where
then everything seems to work out, but this feels a little dodgy.
Trac metadata
Trac field | Value |
---|---|
Version | 6.6.1 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler (Type checker) |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | Unknown |
Architecture | Unknown |