> {-# LANGUAGE Rank2Types #-}I think I finally understand writing code into continuation passing style. I've understood it at an academic level for some time - but that's different from being able to write the code.

> import Control.Monad

This post presents a different implementation of the Maybe monad transformer - usually presented as so:

which can be used to add the notion of short-circuiting failure to any other monad (sortof a simpler version of

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

`ErrorT`from the MTL).

I first came across

`MaybeT`in a page on the Haskell Wiki.

This presentation of MaybeT uses the Church encoding of the data-type:

> newtype MaybeT m a = MaybeT {unMaybeT :: forall b . m b -> (a -> m b) -> m b}Note the similarity to the Prelude function

`maybe`. We can unwrap the transformer like so:

This

> runMaybeT :: Monad m => MaybeT m a -> m (Maybe a)

> runMaybeT m = unMaybeT m (return Nothing) (return . Just)

`runMaybeT`should be a drop-in replacement for the old one.

The advantage here is that we can write the Monad and MonadPlus instances without calling

`bind`or

`return`in the underlying monad

`m`, and without doing any case analysis on

`Just`or

`Nothing`values:

> instance Monad (MaybeT m) whereIt's just a matter of threading the failure and success continuations to the right place at the right time.

> return x = MaybeT $ \_ suc -> suc a

>

> m >>= k = MaybeT $ \fail suc ->

> unMaybeT m fail $ \x ->

> unMaybeT (k x) fail suc

>

> fail _ = mzero

> instance MonadPlus (MaybeT m) where

> mzero = MaybeT $ \fail _ -> fail

>

> m `mplus` n = MaybeT $ \fail suc ->

> unMaybeT m (unMaybeT n fail suc) suc

To show that this is equivalent to the old implementation, here's a re-write of the old

`MaybeT`data constructor from above:

> fromMaybe :: Monad m => m (Maybe a) -> MaybeT m a

> fromMaybe m = MaybeT $ \fail suc -> do

> res <- m

> case res of

> Nothing -> fail

> Just x -> suc x

So anything you can do with the other version, you can do with this version. And for most things it should be a drop-in replacement.