title: Monad transformer – Explicit lifting
body: <p>I'm reading about monad transformers in <em>Real World Haskell</em>. In the following example, the stack is <code>Writer</code> on top <code>State</code> on top of <code>Reader</code> on top of <code>IO</code>. </p>
  
  <pre><code>{-# Language GeneralizedNewtypeDeriving #-}
  
  import Control.Monad
  import Control.Monad.State
  import Control.Monad.Reader
  import Control.Monad.Writer
  import System.Directory
  import System.FilePath
  
  data AppConfig = AppConfig {
        cfgMaxDepth :: Int
      } deriving Show
  
  data AppState = AppState {
        stDeepestReached :: Int
      } deriving Show
  
  newtype MyApp a = MyA {
        runA :: WriterT [(FilePath,Int)] (StateT AppState (ReaderT AppConfig IO)) a
      } deriving (Monad, MonadIO, Functor, MonadReader AppConfig,
                  MonadWriter [(FilePath,Int)], MonadState AppState)
  
  runApp :: MyApp a -&gt; Int -&gt; IO ([(FilePath,Int)], AppState)
  runApp k maxDepth = let config = AppConfig maxDepth
                          state' = AppState 0
                       in runReaderT (runStateT (execWriterT $ runA k) state') config
  
  constrainedCount :: Int -&gt; FilePath -&gt; MyApp ()
  constrainedCount curDepth path = do
    contents &lt;- liftIO . getDirectoryContents $ path
    cfg &lt;- ask
    let maxDepth = cfgMaxDepth cfg
    tell [(path,curDepth)]
    forM_ (filter (\d' -&gt; d' /= ".." &amp;&amp; d' /= ".") contents) $ \d -&gt; do
      let newPath = path &lt;/&gt; d
      isDir &lt;- liftIO $ doesDirectoryExist newPath
      when (isDir &amp;&amp; curDepth &lt; maxDepth) $ do
           let newDepth = curDepth+1
           st &lt;- get
           when (stDeepestReached st &lt; newDepth) $
               put st { stDeepestReached = newDepth }
           constrainedCount newDepth newPath
  
  main = runApp (constrainedCount 0 "/tmp") 2 &gt;&gt;= print
  </code></pre>
  
  <p>I (think I) understand how I can simply call <code>ask</code>, <code>get</code> and <code>put</code> since these are defined in the <code>MonadReader</code>, <code>MonadWriter</code> and <code>MonadState</code> typeclasses and there are instances such as <code>MonadWriter (StateT s m)</code> and so on.</p>
  
  <p>What I <em>don't</em> understand is why I cannot explicit <code>lift</code> an action from the layer below up to the current monad transformer. In <code>constrainedCount</code> I'm in the Reader monad, if I understand correctly, and I thought both <code>st &lt;- get</code> and <code>st &lt;- lift get</code> should work. (And that <code>tell</code> and lift . lift . tell<code>should be the same). If I change</code>st &lt;- get<code>to</code>st &lt;- lift get` I get the error</p>
  
  <pre><code>Couldn't match type `t0 m0' with `MyApp'
  Expected type: MyApp ()
  Actual type: t0 m0 ()
  </code></pre>
  
  <p>which tells me very little... Is my understanding of this completely wrong?</p>