monad变换器中的内部monad是否有`replicateM`函数?

时间:2011-03-16 15:42:52

标签: haskell monads monad-transformers

假设我有这样的事情:

data Environment = ...
data MyState = ...
data Report  = ...

updateState :: Environment -> MyState -> MyState
updateState = ...

report :: MyState -> Report
report = ...

foo :: ReaderT Environment (State MyState) Report 
foo = do env   <- ask
         state <- lift get
         let newState = updateState env state
         lift $ put newState
         return $ report newState

我头脑中的模拟是一个时间过程,我将参数存储在Environment中,动态状态将存储在MyState中,并且我希望每次都收集信息模拟步骤将存储在Report

现在,我不想执行此模拟的许多步骤,并获得包含每个时间步骤的报告的列表。

我通常在没有ReaderT的情况下执行此操作并习惯于传递这样的参数:

 foo :: Enviroment -> State MyState Report

然后我会这样做:

 manySteps :: Int -> Enviroment -> State MyState [Report]
 manySteps n env = replicate n $ (foo env) 

我对liftreplicateM的类型感到困惑。是否有一个组合可以复制变压器内的State MyState monad?

将来我会将ReaderT Environment (State MyState) Report替换为ReaderT Environment (StateT MyState (Rand StdGen)) Report,所以最好在拥有这个怪物类型之前把事情做好:(。

编辑作为一个附带问题 - 是否有比使用ReaderT Environment (State MyState) Report更好的策略?

2 个答案:

答案 0 :(得分:4)

这里复制M的具体示例:

import Control.Monad
import Control.Monad.Reader
import Control.Monad.State

data Environment = E Int deriving Show
data MyState = S Int deriving Show
data Report  = R String deriving Show

updateState :: Environment -> MyState -> MyState
updateState (E step) (S val) = S $! val + step

report :: MyState -> Report
report (S val) = R (show val)

foo :: ReaderT Environment (State MyState) Report 
foo = do env   <- ask
         state <- get -- lift was not needed
         let newState = updateState env state
         put newState -- lift was not needed
         return $ report newState

run e s m = runState (runReaderT m e) s

请注意,我删除了“lift”,因为ReaderT有一个MonadState传递实例。运行foo一次给出:

*Main> run (E 10) (S 5) foo
(R "15",S 15)

我可以连续七次运行foo:

*Main> run (E 10) (S 5) (replicateM 7 foo)
([R "15",R "25",R "35",R "45",R "55",R "65",R "75"],S 75)

上述内容需要进一步澄清吗?

答案 1 :(得分:2)

如果您不确定使用某种方式

,有时候证明类型就足够了
-- import Control.Monad.State
import Control.Monad
import Control.Monad.Trans.Reader

data Environment
data MyState
data Report
data State a b
instance Monad (State a)

foo = undefined :: ReaderT Environment (State MyState) Report

比GHCi

*Main> :t flip replicateM foo
flip replicateM foo
  :: Int -> ReaderT Environment (State MyState) [Report]