Я читаю о преобразователях монад в Real World Haskell. В следующем примере стек 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
Я (думаю, я) понимаю, как я могу просто вызывать ask
, get
и put
, поскольку они определены в классах типов MonadReader
, MonadWriter
и MonadState
и есть такие экземпляры, как MonadWriter (StateT s m)
и так далее.
Чего я не понимаю, так это того, почему я не могу явным образом lift
выполнить действие от уровня ниже до текущего преобразователя монады. В constrainedCount
я в монаде Reader, если я правильно понимаю, и я думал, что и st <- get
, и st <- lift get
должны работать. (А то tell
и поднять. поднять. сказатьshould be the same). If I change
ст ‹- получитьto
ст ‹- поднять получить` я получаю ошибку
Couldn't match type `t0 m0' with `MyApp'
Expected type: MyApp ()
Actual type: t0 m0 ()
что говорит мне очень мало... Мое понимание этого совершенно неверно?
get
не принимает никаких параметров, поэтомуlift . get
не будет работать, потому что(.)
принимает две функции и объединяет их. Вы пробовалиlift get
без состава? - person bheklilr   schedule 29.08.2013lift
действия. - person bheklilr   schedule 30.08.2013