#4485: Unexplained change in type-inference + OverlappingInstances in
---------------------------------+------------------------------------------
    Reporter:  JeremyShaw        |        Owner:                           
        Type:  bug               |       Status:  new                      
    Priority:  normal            |    Milestone:                           
   Component:  Compiler          |      Version:  7.0.1 RC1                
    Keywords:                    |     Testcase:                           
   Blockedby:                    |   Difficulty:                           
          Os:  Unknown/Multiple  |     Blocking:                           
Architecture:  Unknown/Multiple  |      Failure:  GHC rejects valid program
---------------------------------+------------------------------------------
Description changed by igloo:

Old description:

> The behavior of type-inference and OverlappingInstances has changed
> between GHC 6.12 and GHC 7.0 such that the following code type-checks
> under 6.12, but not 7.0rc2. I assume this change has something to do with
> the new type checker in GHC 7, but it is not clear to me if this change
> in behavior is intended. Nor am I clear how to achieve something similar
> to the old behavior. This is preventing HSP (and by extension, happstack)
> from migrating to GHC 7. I reported this earlier on the mailing lists,
> but I have further simplied the test case here.
>
> {{{
> > {-# LANGUAGE TypeFamilies, MultiParamTypeClasses,
> FunctionalDependencies
> >   , FlexibleContexts, FlexibleInstances, UndecidableInstances
> >   , TypeSynonymInstances, GeneralizedNewtypeDeriving
> >   , OverlappingInstances
> >   #-}
> > module XMLGenerator where
> }}}
>

> XMLGenT monad transformer -- not really sure offhand why we have this,
> but we do:
>

> {{{
> > newtype XMLGenT m a = XMLGenT (m a)
> >    deriving (Functor, Monad)
> }}}
>

> next we have a simple class for generating XML
>

> {{{
> > class Monad m => XMLGen m where
> >  type XML m     -- ^ the type that will be used for the generated XML.
> Can be different on a per-monad basis
> >  data Child m   -- ^ the type that will be used for children of an
> element
> >  genElement :: String -> XMLGenT m (XML m) -- ^ a function to generate
> an element with no children or attributes. e.g. <br />
>
> }}}
>
> A class specifying how to turn a value of type 'c' into a list of Child
> elements
>

> {{{
> > class XMLGen m => EmbedAsChild m c where
> >     asChild :: c -> XMLGenT m [Child m]
>
> }}}
>
> Next we have an instance of EmbedAsChild that embeds the XMLGenT
> wrapped 'c' value into 'm' by removing the XMLGenT wrapper,
> (implementation removed since it does not affect the error):
>

> {{{
> > instance (EmbedAsChild m c, m1 ~ m) => EmbedAsChild m (XMLGenT m1 c)
>
> }}}
>
> Now we have an instance which embeds 'XML' as a child. The specific
> type that is considered 'XML' is dependent on the XMLGen instance for
> 'm' (body also removed):
>

> {{{
> > instance (XMLGen m,  XML m ~ x) => EmbedAsChild m x
>
> }}}
>
> Next we define the Identity monad transformer and make it an instance
> of Monad and XMLGen:
>

> {{{
> > data Xml = Xml
> > data IdentityT m a = IdentityT (m a)
> > instance Monad (IdentityT m)
> > instance XMLGen (IdentityT m) where
> >     type XML (IdentityT m) = Xml
>
> }}}
>
> And we also define the Identity monad:
>

> {{{
> > data Identity a = Identity a
> > instance Monad Identity
>
> }}}
>
> Here we specify a way to embed (XMLGenT Identity ()) into IdentityT IO:
>
> {{{
>
> > instance EmbedAsChild (IdentityT IO) (XMLGenT Identity ())
>
> }}}
>
> Next we define some arbitrary type that we want to convert to xml:
>
> {{{
>
> > data FooBar = FooBar
>
> }}}
>
> And now we try to create a more specific EmbedAsChild instance:
>

> {{{
> > instance EmbedAsChild (IdentityT IO) FooBar where
> >   asChild b = asChild $ (genElement "foo")
>
> }}}
>
> Under GHC 6.12, everything type-checks fine. But under GHC 7 we get
> the error:
>

> {{{
> Prelude> :load "../XMLGenerator.lhs"
> [1 of 1] Compiling XMLGenerator     ( ../XMLGenerator.lhs, interpreted )
>
> ../XMLGenerator.lhs:64:17:
>     Overlapping instances for EmbedAsChild
>                                 (IdentityT IO) (XMLGenT m (XML m))
>       arising from a use of `asChild'
>     Matching instances:
>       instance [overlap ok] (m1 ~ m, EmbedAsChild m c) =>
>                             EmbedAsChild m (XMLGenT m1 c)
>         -- Defined at ../XMLGenerator.lhs:31:12-70
>     (The choice depends on the instantiation of `m'
>      To pick the first instance above, use -XIncoherentInstances
>      when compiling the other instance declarations)
>     In the expression: asChild
>     In the expression: asChild $ (genElement "foo")
>     In an equation for `asChild':
>         asChild b = asChild $ (genElement "foo")
> Failed, modules loaded: none.
>
> }}}
>
> I can make the error go away by specifying the type signature of
> genElement explicitly:
>
> {{{
>
> ] instance EmbedAsChild (IdentityT IO) FooBar where
> ]   asChild b = asChild $ ((genElement "foo") :: XMLGenT (IdentityT IO)
> Xml)
>
> }}}
>
> But I would need to do this in dozens of places. (possibly hundreds). So
> that is not very pleasing.
>
> Removing this instance also makes the error go away:
>
> {{{
>
> ] instance EmbedAsChild (IdentityT IO) (XMLGenT Identity ())
>
> }}}
>
> But 'XMLGenT Identity ()' is not a type that genElement can have in
> that context.. Plus I need that instance..
>
> Adding IncoherentInstances changes the error:
>

> {{{
> Prelude> :load "../XMLGenerator.lhs"
> [1 of 1] Compiling XMLGenerator     ( ../XMLGenerator.lhs, interpreted )
>
> ../XMLGenerator.lhs:64:28:
>     Couldn't match type `XMLGenT m (XML m)' with `Xml'
>     In the second argument of `($)', namely `(genElement "foo")'
>     In the expression: asChild $ (genElement "foo")
>     In an equation for `asChild':
>         asChild b = asChild $ (genElement "foo")
> Failed, modules loaded: none.
>
> }}}
>
> I have attached a literate haskell version of this bug report that you
> can test with.
> Thanks!

New description:

 The behavior of type-inference and !OverlappingInstances has changed
 between GHC 6.12 and GHC 7.0 such that the following code type-checks
 under 6.12, but not 7.0rc2. I assume this change has something to do with
 the new type checker in GHC 7, but it is not clear to me if this change in
 behavior is intended. Nor am I clear how to achieve something similar to
 the old behavior. This is preventing HSP (and by extension, happstack)
 from migrating to GHC 7. I reported this earlier on the mailing lists, but
 I have further simplied the test case here.

 {{{
 > {-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FunctionalDependencies
 >   , FlexibleContexts, FlexibleInstances, UndecidableInstances
 >   , TypeSynonymInstances, GeneralizedNewtypeDeriving
 >   , OverlappingInstances
 >   #-}
 > module XMLGenerator where
 }}}


 XMLGenT monad transformer -- not really sure offhand why we have this, but
 we do:


 {{{
 > newtype XMLGenT m a = XMLGenT (m a)
 >    deriving (Functor, Monad)
 }}}


 next we have a simple class for generating XML


 {{{
 > class Monad m => XMLGen m where
 >  type XML m     -- ^ the type that will be used for the generated XML.
 Can be different on a per-monad basis
 >  data Child m   -- ^ the type that will be used for children of an
 element
 >  genElement :: String -> XMLGenT m (XML m) -- ^ a function to generate
 an element with no children or attributes. e.g. <br />

 }}}

 A class specifying how to turn a value of type 'c' into a list of Child
 elements


 {{{
 > class XMLGen m => EmbedAsChild m c where
 >     asChild :: c -> XMLGenT m [Child m]

 }}}

 Next we have an instance of !EmbedAsChild that embeds the XMLGenT
 wrapped 'c' value into 'm' by removing the XMLGenT wrapper,
 (implementation removed since it does not affect the error):


 {{{
 > instance (EmbedAsChild m c, m1 ~ m) => EmbedAsChild m (XMLGenT m1 c)

 }}}

 Now we have an instance which embeds 'XML' as a child. The specific
 type that is considered 'XML' is dependent on the XMLGen instance for
 'm' (body also removed):


 {{{
 > instance (XMLGen m,  XML m ~ x) => EmbedAsChild m x

 }}}

 Next we define the Identity monad transformer and make it an instance
 of Monad and XMLGen:


 {{{
 > data Xml = Xml
 > data IdentityT m a = IdentityT (m a)
 > instance Monad (IdentityT m)
 > instance XMLGen (IdentityT m) where
 >     type XML (IdentityT m) = Xml

 }}}

 And we also define the Identity monad:


 {{{
 > data Identity a = Identity a
 > instance Monad Identity

 }}}

 Here we specify a way to embed (XMLGenT Identity ()) into IdentityT IO:

 {{{

 > instance EmbedAsChild (IdentityT IO) (XMLGenT Identity ())

 }}}

 Next we define some arbitrary type that we want to convert to xml:

 {{{

 > data FooBar = FooBar

 }}}

 And now we try to create a more specific !EmbedAsChild instance:


 {{{
 > instance EmbedAsChild (IdentityT IO) FooBar where
 >   asChild b = asChild $ (genElement "foo")

 }}}

 Under GHC 6.12, everything type-checks fine. But under GHC 7 we get
 the error:


 {{{
 Prelude> :load "../XMLGenerator.lhs"
 [1 of 1] Compiling XMLGenerator     ( ../XMLGenerator.lhs, interpreted )

 ../XMLGenerator.lhs:64:17:
     Overlapping instances for EmbedAsChild
                                 (IdentityT IO) (XMLGenT m (XML m))
       arising from a use of `asChild'
     Matching instances:
       instance [overlap ok] (m1 ~ m, EmbedAsChild m c) =>
                             EmbedAsChild m (XMLGenT m1 c)
         -- Defined at ../XMLGenerator.lhs:31:12-70
     (The choice depends on the instantiation of `m'
      To pick the first instance above, use -XIncoherentInstances
      when compiling the other instance declarations)
     In the expression: asChild
     In the expression: asChild $ (genElement "foo")
     In an equation for `asChild':
         asChild b = asChild $ (genElement "foo")
 Failed, modules loaded: none.

 }}}

 I can make the error go away by specifying the type signature of
 genElement explicitly:

 {{{

 ] instance EmbedAsChild (IdentityT IO) FooBar where
 ]   asChild b = asChild $ ((genElement "foo") :: XMLGenT (IdentityT IO)
 Xml)

 }}}

 But I would need to do this in dozens of places. (possibly hundreds). So
 that is not very pleasing.

 Removing this instance also makes the error go away:

 {{{

 ] instance EmbedAsChild (IdentityT IO) (XMLGenT Identity ())

 }}}

 But 'XMLGenT Identity ()' is not a type that genElement can have in
 that context.. Plus I need that instance..

 Adding !IncoherentInstances changes the error:


 {{{
 Prelude> :load "../XMLGenerator.lhs"
 [1 of 1] Compiling XMLGenerator     ( ../XMLGenerator.lhs, interpreted )

 ../XMLGenerator.lhs:64:28:
     Couldn't match type `XMLGenT m (XML m)' with `Xml'
     In the second argument of `($)', namely `(genElement "foo")'
     In the expression: asChild $ (genElement "foo")
     In an equation for `asChild':
         asChild b = asChild $ (genElement "foo")
 Failed, modules loaded: none.

 }}}

 I have attached a literate haskell version of this bug report that you can
 test with.
 Thanks!

--

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4485#comment:6>
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