You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _chapters/randmonad.md
+56-3Lines changed: 56 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -3,13 +3,66 @@ layout: chapter
3
3
title: "Rand Monad"
4
4
---
5
5
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
+
typeSeed=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 16 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.
7
60
8
61
```haskell
9
62
newtypeRanda=Rand{next::Seed-> (Seed, a) }
10
63
```
11
64
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)`.
13
66
It represents a computation that, given a starting Seed, produces:
14
67
15
68
1.A new updated `Seed`.
@@ -39,7 +92,7 @@ fmap constructs a new Rand value, Rand h, by:
39
92
2. Defining a new function `h` that, given an initial Seed, runs `g` to get `(newSeed, a)`.
40
93
3. Returning `(newSeed, f a)`, where `f a` is the transformed value.
41
94
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).
43
96
44
97
We can also be a bit more succinct, by making use of `fmap` instances
0 commit comments