Can GHC derive Functor and Applicative instances for a monad transformer?
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?
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.
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.