
On Fri, Apr 23, 2010 at 3:46 PM, Dan Doel
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:
class MonadTrans t where 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 :: (MonadTrans t, Monad m, Monad (t m)) => m a -> t m a
lift m = morph (\d -> m >>= d . return)
Ideally, we'd be able to give (forall m. Monad m => Monad (t m)) as a
requirement of MonadTrans. As it happens, my own monad library
simulates that with an extra class.
class MonadTrans t where
return1 :: Monad m => a -> t m a
bind1 :: Monad m => t m a -> (a -> t m b) -> t m b
class MonadTrans t => MonadLift t where
lift :: Monad m => m a -> t m a
This is pretty straightforward to extend:
class MonadLift t => MonadMorph t where
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