#1470: Overlapping (etc) instances
--------------------------------------+-------------------------------------
  Reporter:  igloo                    |          Owner:  simonpj
      Type:  bug                      |         Status:  new    
  Priority:  normal                   |      Milestone:         
 Component:  Compiler (Type checker)  |        Version:  6.6.1  
  Severity:  normal                   |       Keywords:         
Difficulty:  Unknown                  |             Os:  Unknown
  Testcase:                           |   Architecture:  Unknown
--------------------------------------+-------------------------------------
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.

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/1470>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to