假设我有这样的事情:
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)
我对lift
和replicateM
的类型感到困惑。是否有一个组合可以复制变压器内的State MyState
monad?
将来我会将ReaderT Environment (State MyState) Report
替换为ReaderT Environment (StateT MyState (Rand StdGen)) Report
,所以最好在拥有这个怪物类型之前把事情做好:(。
编辑作为一个附带问题 - 是否有比使用ReaderT Environment (State MyState) Report
更好的策略?
答案 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]