2015-10-04 2 views
7

Я пытаюсь реализовать MaybeT в духе библиотеки mtl. При этом не-составителя решения:Может ли GHC получить Functor и аппликативные экземпляры для монадного трансформатора?

{-# 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 сделать это для меня?

+0

Связанный: http://stackoverflow.com/questions/18861231/why-is-there-no-xderiveapplicative-extension – dfeuer

ответ

5

Нет, GHC в настоящее время не может этого сделать. Возможно, в будущем это произойдет.

Необходимость добавления аппликативных экземпляров является довольно новой, представленной с GHC 7.10 и предложением «сжечь все мосты». Это фиксировало некоторые бородавки предыдущей иерархии классов, и, наконец, потребовало, чтобы монады были подклассами аппликаций, которые являются подклассами функторов. К сожалению, это нарушает обратную совместимость и вызывает некоторые неудобства, поскольку нет автоматического способа вывода аппликативных экземпляров.

Возможно, в будущем GHC позволит что-то вроде

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

так, что один не нужно быть явным о суперкласса случаях. Или даже что-то, основанное на шаблоне Haskell, так что писатель библиотеки может объяснить GHC, как автоматически выводить экземпляры (что в некоторой степени возможно сейчас). Мы увидим, что происходит от разработчиков GHC.

+1

Прямо сейчас, есть 'return = pure' по-другому, так что вы можете оставить это , Есть также планы, возможно, сделать 'return' просто синонимом' pure' в будущем. –

2

GHC может быть в состоянии получить экземпляр Functor, так как он довольно хорош в этом. Но единственный способ узнать экземпляр Applicative - это обобщенный вывод нового типа, который здесь не применяется.