<< Previous exercise (3.80) | Index | Next exercise (3.82) >>


 (define (random-update x) 
         (remainder (+ (* 13 x) 5) 24)) 
 (define random-init (random-update (expt 2 32))) 
 ;; assume the operation 'generator and 'reset is a stream,  
 ;; and if the command is 'generator, the element of 
 ;; stream is a string, if the command is 'reset,  
 ;; it is a pair whose first element is 'reset,  
 ;; the other element is the reset value. 
 (define (random-number-generator command-stream) 
         (define random-number 
                 (cons-stream random-init 
                                 (stream-map (lambda (number command)  
                                                                 (cond ((null? command) the-empty-stream) 
                                                                           ((eq? command 'generator) 
                                                                            (random-update number)) 
                                                                           ((and (pair? command)  
                                                                                    (eq? (car command) 'reset)) 
                                                                            (cdr command)) 
                                                                              (error "bad command -- " commmand)))) 


  I think this code has a bug:
  First element in generated stream is always the same - "random-init", even  if command stream started with  'reset OTHER_NUMBER'


 (define (rand-generator commands) 
   (define (rand-helper num remaining-commands) 
     (let ((next-command (stream-car remaining-commands))) 
       (cond ((eq? next-command 'generate) 
              (cons-stream num 
                           (rand-helper (rand-update num) 
                                        (stream-cdr remaining-commands)))) 
             ((pair? next-command) 
              (if (eq? (car next-command) 'reset) 
                  (cons-stream (cdr (stream-car remaining-commands)) 
                      (rand-helper (rand-update (cdr (stream-car remaining-commands))) 
                                   (stream-cdr remaining-commands))) 
                  (error "bad command -- " next-commmand))) 
             (else (error "bad command -- " next-commmand))))) 
   (rand-helper rand-init commands)) 
 ;;; testing 
 ;;; generate stream of commands 
 (define gen-stream  
     (cons 'reset 12) 
     (cons-stream 'generate 
                  (cons-stream (cons 'reset 100) 
                               (cons-stream 'generate 
 (define rands (rand-generator gen-stream)) 
 (stream-ref rands 0) 
 (stream-ref rands 1) 
 (stream-ref rands 2) 
 (stream-ref rands 3) 
 (stream-ref rands 4) 
 (stream-ref rands 5) 
 ;(stream-ref rands 0) 
 ;Value: 12 
 ;(stream-ref rands 1) 
 ;Value: 1033878523 
 ;(stream-ref rands 2) 
 ;Value: 100 
 ;(stream-ref rands 3) 
 ;Value: 1180356723 
 ;(stream-ref rands 4) 
 ;Value: 12 
 ; (stream-ref rands 5) 
 ;Value: 1033878523 


Here is a different solution from mathiebordere's that separates the dispatch on message from the stream construction:

 (define (random-numbers continue-val input-stream) 
   (define (constructor start-val) 
     (cons-stream start-val 
                  (random-numbers (rand-update start-val) 
                                  (stream-cdr input-stream)))) 
   (if (stream-null? input-stream) 
       (let ((msg (stream-car input-stream))) 
         (cond ((eq? msg 'generate) 
                (constructor continue-val)) 
               ((and (pair? msg)(eq? (car msg) 'reset)(number? (cadr msg))) 
                (constructor (cadr msg))) 
                (error "Invalid message found in input-stream" msg))))))