#1549: ghc derives different type signature for equal functions with overlapping
instances
------------------------------+---------------------------------------------
Reporter: int-e | Owner:
Type: proposal | Status: reopened
Priority: low | Milestone:
Component: Documentation | Version: 6.7
Severity: trivial | Resolution:
Keywords: | Difficulty: Unknown
Os: Linux | Testcase:
Architecture: x86 |
------------------------------+---------------------------------------------
Changes (by int-e):
* resolution: invalid =>
* component: Compiler (Type checker) => Documentation
* severity: normal => trivial
* priority: normal => low
* status: closed => reopened
* type: bug => proposal
Old description:
> The code below derives two different type signatures for the same
> function in two different modules.
>
> One of these modules defines a new instance for the `Monad` class. What's
> interesting is that this causes the type checker to derive a more general
> type than before. I think that's a bug.
>
> Another interesting point is that the code below works without -fallow-
> overlapping-instances,
> but if the instances from `A.hs` and from `B.hs` are combined in a single
> file, the compiler complains very loudly. The derived types are
> unaffected by `-fallow-overlapping-instances`.
>
> {{{
> ==> A.hs <==
> {-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
> module A (MaybeT (..), module Control.Monad) where
>
> import Control.Monad
>
> newtype MaybeT m a = MaybeT {runMaybeT :: m (Maybe a)}
>
> instance Monad m => Monad (MaybeT m)
>
> ==> B.hs <==
> {-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
> module B (qqq) where
>
> import A
>
> data Foo a = Foo
>
> instance Monad (MaybeT Foo) where
>
> qqq _ = runMaybeT (runMaybeT (return 1) >> return 2)
>
> ==> C.hs <==
> {-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
> module C (rrr) where
>
> import A
>
> rrr _ = runMaybeT (runMaybeT (return 1) >> return 2)
>
> ==> D.hs <==
> module D (qqq, rrr) where
>
> import B
> import C
>
> {-
> # ghci -fallow-overlapping-instances D.hs
> GHCi, version 6.7.20070716: http://www.haskell.org/ghc/ :? for help
> (...)
> Ok, modules loaded: C, D, A, B.
> *D> :t qqq
> qqq :: (Monad (A.MaybeT m), Num t1) => t -> m (Maybe t1)
> *D> :t rrr
> rrr :: (Monad m, Num t1) => t -> m (Maybe t1)
> *D> :i MaybeT
> newtype MaybeT m a = MaybeT {runMaybeT :: m (Maybe a)}
> -- Defined at A.hs:6:8-13
> instance [overlap ok] (Monad m) => Monad (MaybeT m)
> -- Defined at A.hs:8:0-35
> -}
> }}}
>
> I think that the type derived for `qqq` is correct in the presence of
> overlapping instances.
New description:
Insert "This flag does not change ghc's behaviour when no verlapping
instances are present." after "The -fallow-overlapping-instances lag
instructs GHC to allow more than one instance to match, provided here is a
most specific one." in
http://www.haskell.org/ghc/docs/latest/html/users_guide/type-
extensions.html#instance-overlap
(old description follows for reference)
The code below derives two different type signatures for the same function
in two different modules.
One of these modules defines a new instance for the `Monad` class. What's
interesting is that this causes the type checker to derive a more general
type than before. I think that's a bug.
Another interesting point is that the code below works without -fallow-
overlapping-instances,
but if the instances from `A.hs` and from `B.hs` are combined in a single
file, the compiler complains very loudly. The derived types are unaffected
by `-fallow-overlapping-instances`.
{{{
==> A.hs <==
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
module A (MaybeT (..), module Control.Monad) where
import Control.Monad
newtype MaybeT m a = MaybeT {runMaybeT :: m (Maybe a)}
instance Monad m => Monad (MaybeT m)
==> B.hs <==
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
module B (qqq) where
import A
data Foo a = Foo
instance Monad (MaybeT Foo) where
qqq _ = runMaybeT (runMaybeT (return 1) >> return 2)
==> C.hs <==
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
module C (rrr) where
import A
rrr _ = runMaybeT (runMaybeT (return 1) >> return 2)
==> D.hs <==
module D (qqq, rrr) where
import B
import C
{-
# ghci -fallow-overlapping-instances D.hs
GHCi, version 6.7.20070716: http://www.haskell.org/ghc/ :? for help
(...)
Ok, modules loaded: C, D, A, B.
*D> :t qqq
qqq :: (Monad (A.MaybeT m), Num t1) => t -> m (Maybe t1)
*D> :t rrr
rrr :: (Monad m, Num t1) => t -> m (Maybe t1)
*D> :i MaybeT
newtype MaybeT m a = MaybeT {runMaybeT :: m (Maybe a)}
-- Defined at A.hs:6:8-13
instance [overlap ok] (Monad m) => Monad (MaybeT m)
-- Defined at A.hs:8:0-35
-}
}}}
I think that the type derived for `qqq` is correct in the presence of
overlapping instances.
Comment:
Thank you.
The connection that I hadn't made is that type inference (in particular,
choosing an instance to use for type classes for a monotype) and
constraint simplification (which affects polymorphic types) are really the
same thing.
Once that misconception is resolved the behaviour is just as expected. The
documentation could be clearer about the fact that allowing overlapping
instances does not change the behaviour for the case when none are present
though.
Maybe inserting "This flag does not change ghc's behaviour when no
overlapping instances are present." after "The -fallow-overlapping-
instances flag instructs GHC to allow more than one instance to match,
provided there is a most specific one." would clear that up?
Bertram
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/1549>
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