Introduction to Functional Programming – Random number generation | TDA555 / DIT440, LP1 2016 |

Home | Schedule | Labs | Lectures | Exercises | Exam | About | FAQ | Fire | Forum | TimeEdit | YouTube | Links |

Introduction to Functional Programming – Random number generation | TDA555 / DIT440, LP1 2016 |

Home | Schedule | Labs | Lectures | Exercises | Exam | About | FAQ | Fire | Forum | TimeEdit | YouTube | Links |

The source of this text is a literate Haskell file: random.lhs that you can download and load into GHC.

We begin by importing the module `System.Random`

for random number generation:

`import System.Random`

Random numbers are generated by the function

`randomR :: (Int,Int) -> StdGen -> (Int,StdGen)`

(Here, the type is specialized for `Int`

, but it also works for many other types.)

The first argument is an (inclusive) interval which the result should lie within. The second argument `StdGen`

is an abstract value used determine which random number to generate. The result is a random number and a new `StdGen`

that can be used to generate new random numbers.

To test `randomR`

you first have to create an `StdGen`

. Since `StdGen`

is an abstract type, it can’t be created directly, but only through a helper function, such as:

`mkStdGen :: Int -> StdGen`

Now the user can make up an integer and use that to generate random numbers; e.g:

```
System.Random> fst (randomR (1,10) (mkStdGen 23456))
8
System.Random> fst (randomR (1,10) (mkStdGen 98765))
1
```

If you use the same interval and same `StdGen`

many times, you will always get the same result:

```
System.Random> fst (randomR (1,10) (mkStdGen 23456))
8
System.Random> fst (randomR (1,10) (mkStdGen 23456))
8
```

(After all, `randomR`

is a pure function.)

Now one might wonder what’s the point of all of this. We’re creating a random number from another random number that we had to make up ourselves. But it turns out that it is only for the first use of `randomR`

that one has to create an `StdGen`

. The result from `randomR`

is a pair of a number and a new `StdGen`

. By using the new `StdGen`

to generate the next random number, it is possible to generate a sequence of independent random numbers.

Here is one way to do that:

```
fourRandomNums :: StdGen -> (Int,Int,Int,Int)
fourRandomNums g0 = (a,b,c,d)
where
(a,g1) = randomR (1,10) g0
(b,g2) = randomR (1,10) g1
(c,g3) = randomR (1,10) g2
(d,g4) = randomR (1,10) g3
```

Note how each `randomR`

gets a differet `StdGen`

. The above function generates four random numbers from a single `StdGen`

(a “seed”):

```
*Main> fourRandomNums (mkStdGen 234523)
(4,6,10,1)
```

But as before, we get the same result for the same `StdGen`

:

```
*Main> fourRandomNums (mkStdGen 234523)
(4,6,10,1)
```

This is all you should need for Lab 2, but not the end of the story. What if you want to create a `StdGen`

from a randomly chosen seed? This is a chicken-and-egg problem! Fortunately there is an IO instruction that when executed will fetch a seed from the operating system (which always has a way to generate random values), and use it to create a `StdGen`

:

`newStdGen :: IO StdGen`

We can use `newStdGen`

as follows (but you need to first understand IO before this will make sense!):

```
testFourRandomNums :: IO ()
testFourRandomNums = do
g <- newStdGen
print (fourRandomNums g)
```

Now we can finally generate independent random numbers without having to worry about seeds:

```
*Main> testFourRandomNums
(3,2,7,9)
*Main> testFourRandomNums
(7,6,9,9)
*Main> testFourRandomNums
(2,6,9,5)
```