SICP Exercise 3.6

Question

It is useful to be able to reset a random-number generator to produce a sequence starting from a given value. Design a new rand procedure that is called with an argument that is either the symbol generate or the symbol reset and behaves as follows: (rand 'generate) produces a new random number; ((rand 'reset) ⟨new-value⟩) resets the internal state variable to the designated ⟨new-value⟩. Thus, by resetting the state, one can generate repeatable sequences. These are very handy to have when testing and debugging programs that use random numbers.

Answer

First, we need to define some kind of rand-update method. I will follow the suggestion from the book’s footnotes and use something of the format \(ax+b \bmod m\).

(define (rand-update x)
  (remainder (+ (* 173 x) 33) 101))

Note that this is not a good random algorithm at all. It can only generate numbers up to 101 and it probably does not have a uniform distribution. But it will do the job for testing purposes.

Next, our rand implementation. For this, we just add some conditionals to our \(\lambda\) function:

(define rand
  (let ((x 11))
    (λ (m)
      (cond ((eq? m 'generate)
             (set! x (rand-update x)) x)
            ((eq? m 'reset)
             (λ (x-new) (set! x x-new)))
            (else (error "Unknown request: RAND" m))))))

This uses 11 as random-init. We can test the algorithm by generating three numbers, resetting the initialiser to 11, and generating three more numbers. This second set of numbers should be equivalent to the first.

(rand 'generate)
(rand 'generate)
(rand 'generate)

((rand 'reset) 11)
(rand 'generate)
(rand 'generate)
(rand 'generate)

As we see, this is exactly what happens:

17
45
41
17
45
41