<br><br>
<div><span class="gmail_quote">On 12/17/07, <b class="gmail_sendername">Jack Kelly</b> &lt;<a href="mailto:endgame.dos@gmail.com">endgame.dos@gmail.com</a>&gt; wrote:</span>
<blockquote class="gmail_quote" style="PADDING-LEFT: 1ex; MARGIN: 0px 0px 0px 0.8ex; BORDER-LEFT: #ccc 1px solid">&gt; liftIO $ hPutStrLn h &quot;You lose&quot;<br>&gt; 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>&nbsp;</div>
<div>Actually, this isn&#39;t true.&nbsp; In the case of ReaderT Config IO (), liftIO is the same as lift.</div>
<div>&nbsp;</div>
<div>liftIO exists because it is more general; it works for any monad that is an instance of &quot;MonadIO&quot;, which includes IO, ReaderT&nbsp;r IO, StateT s IO, ReaderT r (StateT s (ErrorT e IO))), etc.</div>
<div>&nbsp;</div>
<div>In the last case, you could write</div>
<div>&nbsp;&nbsp;&nbsp; lift $ lift $ lift $ hPutStrLn h &quot;You lose&quot;</div>
<div>but it&#39;s much simpler to write</div>
<div>&nbsp;&nbsp;&nbsp; liftIO $ hPutStrLn h &quot;You lose&quot;</div>
<div>&nbsp;</div>
<div>Similarily, &quot;ask&quot;&nbsp;is defined in the MonadReader typeclass, which includes Reader, ReaderT IO, and all sorts of other monads that include &quot;Reader&quot; at some level; only the real &quot;reader&quot; monad has a full implementation; the rest are defined in terms of &quot;lift&quot; or simpler operations, like so:
</div>
<div>&nbsp;</div>
<div>instance&nbsp;MonadReader r m =&gt; MonadReader r (StateT s m) where</div>
<div>&nbsp;&nbsp;&nbsp; ask = lift ask</div>
<div>&nbsp;&nbsp;&nbsp; local f m = StateT $ \s -&gt; local f (runStateT m s)</div>
<div>&nbsp;</div>
<div>&nbsp; -- ryan</div><br>&nbsp;</div>