<br><br>
<div><span class="gmail_quote">On 12/17/07, <b class="gmail_sendername">Jack Kelly</b> <<a href="mailto:endgame.dos@gmail.com">endgame.dos@gmail.com</a>> wrote:</span>
<blockquote class="gmail_quote" style="PADDING-LEFT: 1ex; MARGIN: 0px 0px 0px 0.8ex; BORDER-LEFT: #ccc 1px solid">> liftIO $ hPutStrLn h "You lose"<br>> liftIO $ hFlush h<br><br>IO is once again special. For other inner monads, the lift function
<br>does the same thing. Note also that IO has no transformer and must<br>therefore always be the innermost monad.</blockquote>
<div> </div>
<div>Actually, this isn't true. In the case of ReaderT Config IO (), liftIO is the same as lift.</div>
<div> </div>
<div>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.</div>
<div> </div>
<div>In the last case, you could write</div>
<div> lift $ lift $ lift $ hPutStrLn h "You lose"</div>
<div>but it's much simpler to write</div>
<div> liftIO $ hPutStrLn h "You lose"</div>
<div> </div>
<div>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:
</div>
<div> </div>
<div>instance MonadReader r m => MonadReader r (StateT s m) where</div>
<div> ask = lift ask</div>
<div> local f m = StateT $ \s -> local f (runStateT m s)</div>
<div> </div>
<div> -- ryan</div><br> </div>