GHC能否为一个Monad Transformer派生Functor和Applicative实例?

8
我正在尝试按照mtl库的思路实现MaybeT。以下是无法编译的解决方案:
{-# 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

...

我遇到了以下错误:

无法推断出(来自上下文(Monad m)的实例声明的超类)(MaybeT m的应用程序)

如果我实现以下内容,则可以编译:

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

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

GHC 能为我做到这一点吗?


相关:https://dev59.com/x2Mk5IYBdhLWcg3w6x_h - dfeuer
2个回答

6
不,GHC目前无法做到这一点。也许将来会有这个功能。
添加applicative实例的需求是相当新的,是在GHC 7.10和“烧掉所有桥梁”提案中引入的。通过最终要求monad是applicative的子类,而applicative是functor的子类,解决了先前类层次结构的一些问题。不幸的是,这破坏了向后兼容性,并且会导致一些不便,因为没有自动推断applicative实例的方式。
也许在将来,GHC将允许类似以下的操作:
class Applicative m => Monad m where
   return :: a -> m a
   (>>=) :: m a -> (a -> m b) -> m b
   default pure = return
   default (<*>) = ap

这样就不需要明确指定超类实例。或者基于模板哈斯克尔语言,库作者可以向 GHC 解释如何自动派生实例(在某种程度上,这是可行的)。我们将看到 GHC 开发人员会有什么成果。


1
现在,有一个return = pure的默认设置,所以你可以省略它。未来也有可能将return变成pure的同义词。 - Ørjan Johansen

2

GHC可能能够推导出Functor实例,因为它在这方面表现得相当不错。但是它知道推导一个Applicative实例的唯一方法是使用广义新类型推导,而这种方法在此处不适用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接