
On 12/17/07, Jack Kelly
liftIO $ hPutStrLn h "You lose" liftIO $ hFlush h
IO is once again special. For other inner monads, the lift function does the same thing. Note also that IO has no transformer and must therefore always be the innermost monad.
Actually, this isn't true. In the case of ReaderT Config IO (), liftIO is the same as lift. liftIO exists because it is more general; it works for any monad that is an instance of "MonadIO", which includes IO, ReaderT r IO, StateT s IO, ReaderT r (StateT s (ErrorT e IO))), etc. In the last case, you could write lift $ lift $ lift $ hPutStrLn h "You lose" but it's much simpler to write liftIO $ hPutStrLn h "You lose" Similarily, "ask" is defined in the MonadReader typeclass, which includes Reader, ReaderT IO, and all sorts of other monads that include "Reader" at some level; only the real "reader" monad has a full implementation; the rest are defined in terms of "lift" or simpler operations, like so: instance MonadReader r m => MonadReader r (StateT s m) where ask = lift ask local f m = StateT $ \s -> local f (runStateT m s) -- ryan