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

```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 <dan.doel at gmail.com> wrote:
>>>
>>> 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

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
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 <dave at zednenem.com>
<http://www.eyrie.org/~zednenem/>
```