[Haskell-beginners] Combining the Rand and State monads

Amy de Buitléir amy at nualeargais.ie
Thu Apr 5 12:42:20 CEST 2012

I'm trying to develop a very simple simulation framework. A simulation consists
of a list of models. Models generate output events based on an input event. Here
is what I have currently (it works fine).

import Data.List (foldl')
import Control.Monad.State ( get, gets, modify, put, runState, State )

type Event = Char

type Environment = String

-- | Given an event, a model generates zero or more new events
type Model = Event -> State Environment [Event]

modelA :: Model
modelA a = do
  s <- get
  put $ s ++ a:"A "
  return $ a:"hip "

modelT :: Model
modelT a = do
  s <- get
  put $ s ++ a:"T "
  return $ a:"hop "

-- | Process a sequence of events using one model
runModel :: Model -> [Event] -> State Environment [Event]
runModel m [] = return []
runModel m (e:es) = do
  s <- get
  let (es', s') = runState (m e) s
  let (es'', s'') = runState (runModel m es) s'
  put s''
  return $ es' ++ es''

-- | Process a sequence of events using multiple models
runModels :: [Model] -> [Event] -> State Environment [Event]
runModels [] es = return []
runModels (m:ms) es = do
  s <- get
  let (es', s') = runState (runModel m es) s
  let (es'', s'') = runState (runModels ms es) s'
  put s''
  return $ es' ++ es''

Now what I want to do is to give models the ability to generate random numbers.
So I thought I might change the definition of Model to:

type Model g = Event -> StateT Environment (Rand g) [Event]

And then I could alter one of the models to use random numbers like so:

modelT :: Model g
modelT _ = do
  s <- get
  put $ s ++ " R"
  return [n]

I can't figure out how to get a random number from the inner monad. I assume I
use lift, but I can't get it to work. Would it be better to use RandT instead of
StateT? (And if so, how would I do the state operations?)

Thank you in advance for any help!

More information about the Beginners mailing list