David Menendez dave at zednenem.com
Fri Apr 23 16:36:35 EDT 2010

```On Fri, Apr 23, 2010 at 3:46 PM, Dan Doel <dan.doel at gmail.com> wrote:
> On Friday 23 April 2010 1:39:36 pm Anders Kaseorg wrote:
>> On Fri, 23 Apr 2010, Tyson Whitehead wrote:
>> > Are you then saying that liftIO should be able to be defined via
>> > morphIO?  I would be curious to see that as, after a bit of trying, I
>> > still can't see how to.  Specifically, I can't capture the results of
>> > the desired IO operation.
>>
>> Yes, just like lift is defined via morph:
>>
>> liftIO' :: (MonadMorphIO m) => IO a -> m a
>> liftIO' m = morphIO \$ \down -> m >>= down . return
>>
>> main = runContT (runReaderT main' ()) return
>> main' = do
>>   liftIO' \$ putStrLn "What is your name?"
>>   name <- liftIO' \$ getLine
>>   liftIO' \$ putStrLn \$ "Hello " ++ name
>
> Can lift really be defined from morph, though? Given just:
>
>    morph :: Monad m => (forall b. (t m a -> m b) -> m b) -> t m a
>
> trying to define:
>
>  lift :: (Monad m, MonadTrans t) => m a -> t m a
>  lift m = morph (\k -> m >>= k . return)
>
> yields an error. Monad m and MonadTrans t do not imply Monad (t m), which is
> what that definition requires.

This works for me:

lift m = morph (\d -> m >>= d . return)

Ideally, we'd be able to give (forall m. Monad m => Monad (t m)) as a
simulates that with an extra class.

return1 :: Monad m => a -> t m a
bind1 :: Monad m => t m a -> (a -> t m b) -> t m b

lift :: Monad m => m a -> t m a

This is pretty straightforward to extend:

morph :: Monad m => (forall b. (t m a -> m b) -> m b) -> t m a

lift_ :: (MonadMorph t, Monad m) => m a -> t m a
lift_ m = morph (\d -> m >>= d . return1)

The question I would ask is whether morph can be sensibly defined for
the backtracking monad. It's a good example of a class of monads which
are more complicated than the usual state and exceptions stuff, but
not as powerful or complex as ContT.

--
Dave Menendez <dave at zednenem.com>
<http://www.eyrie.org/~zednenem/>
```