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