我在读关于真实世界中的单台变压器的文章。在下面的示例中,堆栈是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
st <-获取to
st <- lift‘i得到错误
Couldn't match type `t0 m0' with `MyApp'
Expected type: MyApp ()
Actual type: t0 m0 ()
这几乎没有告诉我..。我对这件事的理解完全错误吗?
发布于 2013-08-29 20:11:54
让我们看看lift get
的类型
lift get :: (MonadTrans t, MonadState a m) => t m a
但是你的MyApp
不是一个单一的变压器,它只是一个单一的。但内在的是,当然,如果你用
st <- MyA $ lift get
它起作用了。
https://stackoverflow.com/questions/18519774
复制相似问题