{Weber} Pages 32, 38
To continue our GAUSSIAN example (see {Note Gaussian}), we can try to remove the side-effect from RANDOM while avoiding the passing around of SEED by pushing RANDOM up to the top level (see Figure N10). RANDOM-DRIVER takes a function F and an initial seed (reminiscent of <THE-PRIMITIVE-PROCEDURES>), and continually stuffs random numbers into F. Each call to F must produce a new F (a kind of continuation [Reynolds]). Using this, we can arrange for numbers with a "Gaussian" distribution to be generated.
(DEFINE (RANDOM-DRIVER F SEED)
((LAMBDA (NEWSEED)
(RANDOM-DRIVER (F NEWSEED) NEWSEED))
((LAMBDA (Z)
(COND ((> Z 0) Z)
(T (+ Z -32768.))))
(* SEED 899.))))
(DEFINE (GAUSSIAN G)
(WEBER 0 43 G))
(DEFINE (WEBER X N H)
(COND ((= N 0) (H X))
(T (LAMBDA (R)
(WEBER (+ X R) (- N 1) H)))))
(DEFINE (DRIVER USERFN INITSEED)
(RANDOM-DRIVER (GAUSSIAN USERFN) INITSEED))
Figure N10
"Gaussian" Pseudo-Random Number Generator without Passing SEED
Around
In this way, a user function can be provided to DRIVER (along with the initial seed), and the user function will have "Gaussian" numbers stuffed into it. For example:
(DEFINE (P R) (PROGN (PRINT R) P))
(DRIVER P 11)
will print an interminable sequence of "Gaussian" numbers. Notice the structure of the program: the RANDOM procedure calls GAUSSIAN, which in turn calls the user procedure. We have completely everted the overall system. The more layers in the original system piled on top of GAUSSIAN, the more layers will appear inside-out in this version.
Now there are two other funny things about this. One is that we had to use a side effect (PRINT) to get the answer out; the other is that