10
votes

I have the following code:

{-# LANGUAGE DefaultSignatures#-}

import Control.Monad.Trans.Class
import Control.Monad.Trans.Maybe

class Monad m => MonadMaybe m where
  liftMaybe :: Maybe a -> m a
  default liftMaybe :: (MonadTrans t, MonadMaybe m) => Maybe a -> t m a
  liftMaybe = lift . liftMaybe

instance MonadMaybe m => MonadMaybe (MaybeT m)

Using The Glorious Glasgow Haskell Compilation System, version 8.0.1.20161117, this fails to compile:

foo.hs:11:10: error:
    • Couldn't match type ‘m’ with ‘MaybeT m’
      ‘m’ is a rigid type variable bound by
        the instance declaration at foo.hs:11:10
      Expected type: Maybe a -> MaybeT m a
        Actual type: Maybe a -> MaybeT (MaybeT m) a
    • In the expression: Main.$dmliftMaybe @MaybeT m
      In an equation for ‘liftMaybe’:
          liftMaybe = Main.$dmliftMaybe @MaybeT m
      In the instance declaration for ‘MonadMaybe (MaybeT m)’
    • Relevant bindings include
        liftMaybe :: Maybe a -> MaybeT m a (bound at foo.hs:11:10)

However in GHC 7.10, this compiles without a problem.

Is GHC 8 correct, or have I found a bug?

1
Out of curiosity, does it work if you change the m in the default signature to another type variable, like n, or add an explicit forall? I’m wondering if GHC is treating m as a scoped type variable here for some reason.Alexis King
Your code also typechecks in the stable release of GHC 8.0.1 .duplode
@AlexisKing, that's essentially the issue. Occurrences of the head of the class declaration (here m) are always scoped in the body, otherwise there would be no relation between m and the type of the methods!Reid Barton
@ReidBarton Right, of course, that makes sense—it seems obvious in retrospect. :)Alexis King

1 Answers

9
votes

Despite GHC 7.10 accepting it, your code actually makes no sense. See https://ghc.haskell.org/trac/ghc/ticket/12784 for discussion.