Suppose I have something like this:
data Environment = ...
data MyState = ...开发者_如何学C
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
What's in my head are simulations of a time process in which I have parameters that will be stored in Environment
, the dynamical state will be stored in MyState
and info I wish to collect in each time step of the simulation will be stored in Report
.
Now, I wan't to run many steps of this simulation and get a list with the reports for each time step.
I usually did this without a ReaderT
and used to pass the parameters like this:
foo :: Enviroment -> State MyState Report
Then I would just do:
manySteps :: Int -> Enviroment -> State MyState [Report]
manySteps n env = replicate n $ (foo env)
I'm getting confused with the types of lift
and replicateM
. Is there a combination that would replicate the State MyState
monad inside the transformer?
In the future I'll replace ReaderT Environment (State MyState) Report
for ReaderT Environment (StateT MyState (Rand StdGen)) Report
so it's better to get things right before having this monster type :(.
edit: as a side question - is there a better strategy than using ReaderT Environment (State MyState) Report
?
A concrete example of replicateM here:
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
Note that I removed the "lift" since the ReaderT has a MonadState pass-through instance. Running foo once gives:
*Main> run (E 10) (S 5) foo
(R "15",S 15)
I can run foo seven times in a row:
*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)
What in the above needs more clarification?
Sometimes it's enough to prove type if you unsure in the way to use something
-- 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
Than in GHCi
*Main> :t flip replicateM foo
flip replicateM foo
:: Int -> ReaderT Environment (State MyState) [Report]
精彩评论