我正在尝试以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
...
我收到错误:
无法推断(Applicative(MaybeT m))产生的 来自上下文的实例声明的超类(Monad m)
如果我实现以下内容,则编译:
instance (Monad m) => Applicative (MaybeT m) where
pure = return
(<*>) = ap
instance (Monad m) => Functor (MaybeT m) where
fmap = liftM
GHC可以为我做这件事吗?
答案 0 :(得分:6)
不,GHC目前无法做到这一点。也许将来它会。
添加应用实例的需求是一个相当新的实例,在GHC 7.10和“烧掉所有桥梁”提案中引入。这修复了前一个类层次结构的一些瑕疵,最后要求monad是作为子函数的子类的应用程序的子类。不幸的是,这会破坏向后兼容性,并导致一些不便,因为没有自动推断应用实例的方法。
也许将来GHC会允许像
这样的东西class Applicative m => Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
default pure = return
default (<*>) = ap
这样就不需要明确超类实例了。甚至基于Template Haskell的东西,以便库编写者可以向GHC解释如何自动派生实例(在某种程度上,这在当前是可行的)。我们将看到来自GHC开发人员的内容。
答案 1 :(得分:2)
GHC很可能能够推导出Functor
个实例,因为它相当不错。但它知道派生Applicative
实例的唯一方法是使用广义newtype派生,这里不适用。