Let it start from the beginning:
type Rand a = State StdGen a
This line tells you that Rand a
is a type synonym for State
, whose state is specified by StdGen
and whose final value is of type a
. This will be used to store the state of the random number generator between each request for a random number.
The getRandom
code can be converted to a notation:
getRandom :: (Random a) => Rand a getRandom = do r <- get -- get the current state of the generator let (a,g) = random r in do -- call the function random :: StdGen -> (a, StdGen) put g -- store the new state of the generator return a -- return the random number that was generated
The runRand
function takes an initial seed n
and a value r
type Rand a
(which, remember, is simply a synonym for State StdGen a
). It creates a new generator with mkStdGen n
and passes it to evalState r
. The evalState
function simply evaluates the return value of type State sa
, ignoring the state.
Again, we can convert runRandIO
to do
:
runRandIO :: Rand a -> IO a runRandIO r = do rnd <- randomIO -- generate a new random number using randomIO return (runRand rnd r) -- use that number as the initial seed for runRand
Finally, getRandoms
takes a number n
representing the number of random values ββthat you want to generate. It creates a list [1..n]
and applies getRandom
to the list. Please note that the actual values ββin [1..n]
not used (you can tell because the lambda function starts with \_ -> ...
). There is only something in the list with the correct number of items. Since getRandom
returns a monadic value, we use mapM
to match on a list that causes the state (i.e., StdGen
) to draw correctly through each of the getRandom
calls.
source share