8
votes

I'm trying to implement MaybeT in the spirit of the mtl library. With this non-compiling solution:

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances #-}

import Control.Monad
import Control.Monad.Trans
import Control.Monad.State

newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

instance (Monad m) => Monad (MaybeT m) where
    x >>= f = MaybeT $ runMaybeT x >>= maybe (return Nothing) (runMaybeT . f)
    return a = MaybeT $ return (Just a)
    fail _ = MaybeT $ return Nothing

instance MonadTrans MaybeT where
     lift m = MaybeT (liftM Just m)

instance (MonadIO m) => MonadIO (MaybeT m) where
    liftIO m = lift (liftIO m)

instance (MonadState s m) => MonadState s (MaybeT m) where
    get = lift get
    put = lift . put

...

I get the error:

Could not deduce (Applicative (MaybeT m)) arising from the superclasses of an instance declaration from the context (Monad m)

If I implement the following, it compiles:

instance (Monad m) => Applicative (MaybeT m) where
    pure = return
    (<*>) = ap 

instance (Monad m) => Functor (MaybeT m) where
    fmap = liftM

Can GHC do this for me?

2

2 Answers

7
votes

No, GHC can not currently do that. Maybe in the future it will.

The need to add applicative instances is a fairly new one, introduced with GHC 7.10 and the "burn all bridges" proposal. This fixed some warts of the previous class hierarchy, by finally requiring that monads are subclasses of applicatives which are subclasses of functors. Unfortunately, this breaks backward compatibility, and causes some inconveniences since there's no automatic way to infer the applicative instances.

Perhaps in the future GHC will allow something like

class Applicative m => Monad m where
   return :: a -> m a
   (>>=) :: m a -> (a -> m b) -> m b
   default pure = return
   default (<*>) = ap

so that one does not need to be explicit about the superclass instances. Or even something based on Template Haskell, so that a library writer can explain to GHC how to automatically derive instances (which, to some extent, is feasible right now). We shall see what comes from the GHC developers.

2
votes

GHC may well be able to derive the Functor instance, since it's fairly good at those. But the only way it knows to derive an Applicative instance is with generalized newtype deriving, which does not apply here.