
On Fri, Apr 23, 2010 at 9:09 PM, wren ng thornton
David Menendez wrote:
On Fri, Apr 23, 2010 at 3:46 PM, Dan Doel
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
exceptions).
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