GHC 可以为 monad 转换器派生 Functor 和 Applicative 实例吗?

Can GHC derive Functor and Applicative instances for a monad transformer?

我正在努力实现 MaybeT 本着 mtl 库的精神。使用此非编译解决方案:

{-# 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

...

我收到错误:

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

如果我执行以下内容,它会编译:

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

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

GHC 可以帮我做这个吗?

GHC 很可能能够导出 Functor 实例,因为它在这些方面相当出色。但是它知道派生 Applicative 实例的唯一方法是使用广义的新类型派生,这在这里不适用。

不,GHC 目前无法做到这一点。也许以后会。

添加应用实例的需求是一个相当新的需求,在 GHC 7.10 和 "burn all bridges" 提案中引入。这修复了之前 class 层次结构的一些缺陷,最终要求 monad 是应用程序的子class,而应用是函子的子class。不幸的是,这会破坏向后兼容性,并造成一些不便,因为没有自动推断适用实例的方法。

也许将来 GHC 会允许像

这样的东西
class Applicative m => Monad m where
   return :: a -> m a
   (>>=) :: m a -> (a -> m b) -> m b
   default pure = return
   default (<*>) = ap

这样就不需要明确说明 superclass 实例。或者甚至是基于模板 Haskell 的东西,这样库编写者就可以向 GHC 解释如何自动派生实例(在某种程度上,现在是可行的)。我们将看到来自 GHC 开发人员的内容。