Monad变压器 - 显式提升

时间:2013-08-29 19:48:50

标签: monads monad-transformers haskell lifting

我正在阅读 Real World Haskell 中的monad变换器。在以下示例中,堆栈Writer位于State之上的Reader之上IO

{-# 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 -> Int -> IO ([(FilePath,Int)], AppState)
runApp k maxDepth = let config = AppConfig maxDepth
                        state' = AppState 0
                     in runReaderT (runStateT (execWriterT $ runA k) state') config

constrainedCount :: Int -> FilePath -> MyApp ()
constrainedCount curDepth path = do
  contents <- liftIO . getDirectoryContents $ path
  cfg <- ask
  let maxDepth = cfgMaxDepth cfg
  tell [(path,curDepth)]
  forM_ (filter (\d' -> d' /= ".." && d' /= ".") contents) $ \d -> do
    let newPath = path </> d
    isDir <- liftIO $ doesDirectoryExist newPath
    when (isDir && curDepth < maxDepth) $ do
         let newDepth = curDepth+1
         st <- get
         when (stDeepestReached st < newDepth) $
             put st { stDeepestReached = newDepth }
         constrainedCount newDepth newPath

main = runApp (constrainedCount 0 "/tmp") 2 >>= print

我(我想)了解我如何简单地致电askgetput,因为这些是MonadReaderMonadWriter和{ {1}}类型类,有MonadState等实例。

理解的是为什么我不能明确MonadWriter (StateT s m)从下面的层到当前monad变换器的动作。在lift我是读者monad,如果我理解正确,我认为constrainedCountst <- get都应该有用。 (并st <- lift get并举起电梯。告诉tell st&lt; - get should be the same). If I change st&lt; - lift get`我收到错误

to

告诉我很少......我对此的理解是完全错误的吗?

1 个答案:

答案 0 :(得分:9)

让我们看一下lift get的类型:

lift get :: (MonadTrans t, MonadState a m) => t m a

但你的MyApp不是monad变换器,它只是一个monad。但当然,内在的是,如果你使用

    st <- MyA $ lift get

它有效。