Move MonadIO to base

David Menendez dave at
Fri Apr 23 21:55:52 EDT 2010

On Fri, Apr 23, 2010 at 9:09 PM, wren ng thornton
<wren at> wrote:
> David Menendez wrote:
>> On Fri, Apr 23, 2010 at 3:46 PM, Dan Doel <dan.doel at> wrote:
>>> Monad m and MonadTrans t do not imply Monad (t m), which is
>>> what that definition requires.
>> This works for me:
>> lift :: (MonadTrans t, Monad m, Monad (t m)) => m a -> t m a
>> lift m = morph (\d -> m >>= d . return)
> I think the point was that the current definition of lift does not have a
> Monad(t m) constraint and therefore the above definition doesn't suffice
> because it imposes additional requirements. (Granted they're desirable
> requirements, but all the same.)

It makes explicit certain implicit requirements. Instances of
MonadTrans are intended to map monads to monads (forall m. Monad m =>
Monad (t m)).

Admittedly, the MTL is woefully under-specified, but you would expect
lift to satisfy these properties:

   lift (return x) = return x
   lift (e >>= f) = lift e >>= lift . f

which are only meaningful if there's an implicit Monad (t m) constraint on lift.

In any case, I don't think anyone is talking about adding morph to the
standard monad libraries yet. It's only general enough to promote a
subset of monad operations (mplus and catch), and it only applies to a
subset of monad transformers (state reader/writer/transformer and

N.B. The instance given for ContT does not do what you want. Here's
the definition again:

   morphIO f = ContT $ \k -> morphIO (\d -> f (\m -> d (runContT m k)))

Note that the entire continuation is passed to d. If you are defining,
say, block in terms of morphIO

   gblock m = morphIO (\d -> block (d m))

Then m and its continuation get masked, not just m. Similar problems
occur for backtracking monads and iteratees.

Dave Menendez <dave at>

More information about the Libraries mailing list