Skip to content

Commit 4ace5a6

Browse files
committed
more info
1 parent 1078c8e commit 4ace5a6

File tree

1 file changed

+56
-3
lines changed

1 file changed

+56
-3
lines changed

_chapters/randmonad.md

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,66 @@ layout: chapter
33
title: "Rand Monad"
44
---
55

6-
# Rand Monad
6+
Pseudorandom number generators create a sequence of unpredictable numbers.
7+
The following function generates the next element in a pseudorandom sequence from a previous seed.
8+
9+
```haskell
10+
type Seed = Int
11+
12+
nextRand :: Seed -> Seed
13+
nextRand prevSeed = (a*prevSeed + c) `mod` m
14+
where -- Parameters for linear congruential RNG.
15+
a = 1664525
16+
c = 1013904223
17+
m = 2^32
18+
```
19+
20+
From a given seed in the pseudorandom sequence we can generate a number in a specified range.
21+
22+
```haskell
23+
-- | Generate a number between `l` and `u`, inclusive.
24+
genRand :: Int -> Int -> Seed -> Int
25+
genRand l u seed = seed `mod` (u-l+1) + l
26+
```
27+
28+
For example:
29+
30+
```haskell
31+
-- | Roll a six-sided die once.
32+
-- >>> rollDie1 123
33+
-- (5,1218640798)
34+
-- >>> rollDie1 1218640798
35+
-- (4,1868869221)
36+
-- >>> rollDie1 1868869221
37+
-- (1,166005888)
38+
rollDie1 :: Seed -> (Int, Seed)
39+
rollDie1 s =
40+
let s' = nextRand s
41+
n = genRand 1 6 s'
42+
in (n, s')
43+
```
44+
45+
And if we want a sequence of dice rolls:
46+
47+
```haskell
48+
-- | Roll a six-sided die `n` times.
49+
-- >>> diceRolls1 3 123
50+
-- ([5,4,1],166005888)
51+
diceRolls1 :: Int -> Seed -> ([Int], Seed)
52+
diceRolls1 0 s = ([], s)
53+
diceRolls1 n s =
54+
let (r, s') = rollDie1 s
55+
(rolls, s'') = diceRolls1 (n-1) s'
56+
in (r:rolls, s'')
57+
```
58+
59+
But keeping track of the various seeds (`s`,`s'`,`s''`) is tedious and error prone. Let's invent a monad which manages the seed for us.
760

861
```haskell
962
newtype Rand a = Rand { next :: Seed -> (Seed, a) }
1063
```
1164

12-
`Rand` is a newtype wrapper around a function `Seed -> (Seed, a)`.
65+
`Rand` is a `newtype` wrapper around a function with type `Seed -> (Seed, a)`.
1366
It represents a computation that, given a starting Seed, produces:
1467

1568
1. A new updated `Seed`.
@@ -39,7 +92,7 @@ fmap constructs a new Rand value, Rand h, by:
3992
2. Defining a new function `h` that, given an initial Seed, runs `g` to get `(newSeed, a)`.
4093
3. Returning `(newSeed, f a)`, where `f a` is the transformed value.
4194

42-
After applying fmap f, we have a new random computation that takes the same Seed as input and produces a transformed value (f a), while maintaining the same mechanics of randomness (i.e., correctly passing and updating the Seed state).
95+
After applying `fmap f`, we have a new random computation that takes the same Seed as input and produces a transformed value `(f a)`, while maintaining the same mechanics of randomness (i.e., correctly passing and updating the Seed state).
4396

4497
We can also be a bit more succinct, by making use of `fmap` instances
4598

0 commit comments

Comments
 (0)