2010-05-01 20 views
4

Je suis en train de construire un MaybeT-transformateur Monad, basé sur l'exemple dans le Haskell Real World , Chapitre Monad Transformateurs:Comment est-ce que je peux faire un MaybeT de Maybe-Transformer dans une instance de MonadWriter?

data MaybeT m a = MaybeT { runMT :: m (Maybe a) } 

instance (Monad m) => Monad (MaybeT m) where 
    m >>= f = MaybeT $ do a <- runMT m 
         case a of 
          Just x -> runMT (f x) 
          Nothing -> return Nothing 
    return a = MaybeT $ return (Just a) 

instance MonadTrans MaybeT where 
    lift m = MaybeT $ do 
        a <- m 
        return (Just a) 

Cela fonctionne bien, mais maintenant je veux faire MaybeT un instance de MonadWriter:

instance (MonadWriter w m) => MonadWriter w (MaybeT m) where 
tell = lift . tell 
listen m = MaybeT $ do unwrapped <- listen (runMT m) 
         return (Just unwrapped) 

le dire est ok, mais je ne peux pas obtenir le droit de la fonction écouter. Le meilleur que je pourrais trouver après 1 1/2 jours d'origami constructeur est celui que vous voyez ci-dessus: déballé est censé être un tuple de (Peut-être, w), et que je veux conclure dans un Peut-être -Type et mettre le tout dans un MonadWriter vide.

Mais le compilateur se plaint avec:

Occurs check: cannot construct the infinite type: a = Maybe a 
    When generalising the type(s) for `listen' 
    In the instance declaration for `MonadWriter w (MaybeT m)' 

Qu'est-ce que je manque?

Répondre

6

listen a le type signature

m a -> m (a, w) 

à savoir

MaybeT m a -> MaybeT m (a, w) 

Mais MaybeT $ listen (runMT m) >>= return . Just a le type signature

MaybeT m a -> MaybeT m (Maybe a, w) 

si l'erreur de type infini est élevé. Vous devez convertir cette unwrapped :: (Maybe a, w) en Maybe (a, w) procéder:

listen m = MaybeT $ do (val, wr) <- listen (runMT m) 
        case val of 
         Nothing -> return Nothing 
         Just x -> return (Just (x, wr)) 

(BTW, il y a une mise en œuvre de MaybeT dans http://www.haskell.org/haskellwiki/New_monads/MaybeT.)

+0

@KennyTM: Merci beaucoup! Très rapide et très précis! – martingw