Question

Suppose I have something like this:

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

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 ?

Was it helpful?

Solution

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?

OTHER TIPS

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]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top