Я читаю о трансформаторах монады в Real World Haskell. В следующем примере стек равен Writer
сверху State
поверх Reader
поверх IO
.Monad transformer - Явный подъем
{-# 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
Я нахожусь в монаде читателя, если я правильно понимаю, и я думал, что должны работать и st <- get
, и st <- lift get
. .. (И это tell
и лифт лифта сказать should be the same). If I change
ул < - получить to
ул < - подъемную get` я получаю ошибку
Couldn't match type `t0 m0' with `MyApp'
Expected type: MyApp()
Actual type: t0 m0()
, который говорит мне, очень мало ... Это мое понимание этого совершенно неправильно
?
IIRC, 'get' не принимает никаких параметров, поэтому' lift. get' не будет работать, потому что '(.)' принимает две функции и составляет их. Вы пробовали 'lift get' без композиции? – bheklilr
Ух, мой плохой. Благодаря! Я обновил этот вопрос сейчас. – beta
Чтобы (возможно) ответить на ваш вопрос, я думаю, это потому, что он завернут в новый тип. Я не знаю, почему вы хотите явно «поднять» действия. – bheklilr