sicp-ex-3.6



<< Previous exercise (3.5) | Index | Next exercise (3.7) >>


 (define rand 
   (let ((x random-init)) 
     (define (dispatch message) 
       (cond ((eq? message 'generate) 
               (begin (set! x (rand-update x)) 
                      x)) 
             ((eq? message 'reset) 
               (lambda (new-value) (set! x new-value))))) 
     dispatch)) 

Test:

 (define random-init 0) 
 (define (rand-update x) (+ x 1)) ; A not-very-evolved PNRG 
 (rand 'generate) 
 ; 1 
 (rand 'generate) 
 ; 2 
 ((rand 'reset) 0) 
 ; 0 
 (rand 'generate) 
 ; 1 

It's interesting to notice that the lambda returned by a call to (rand 'reset) still has the closure we created as lexical scope:

 x 
 ; Error: undefined variable 'x'. 

hi-artem

Here, inside (cond ..) construct, using "begin" is unnecessary.


Shawn

We could also define rand as a procedure instead of a variable:

  
 (define (rand arg) 
   (let ((x random-init)) 
     (cond ((eq? arg 'generate) 
            (set! x (rand-update x)) 
            x) 
           ((eq? arg 'reset) 
            (lambda (new-value) (set! x new-value)))))) 

pa3

Shawn's version will not work actually. It will always return the result of evaluating (rand-update random-input), because the state (x variable) is being recreated and reset to random-input each time rand function invoked.


joew

 #lang sicp 
 ;"random" number generator 
 (define (rand-update x) 
   (let ((a 27) (b 26) (m 127)) 
     (modulo (+ (* a x) b) m))) 
  
 (define x1 (rand-update 0)) 
 (define x2 (rand-update x1)) 
 (define x3 (rand-update x2)) 
 (define x4 (rand-update x3)) 
 (define x5 (rand-update x4)) 
 x1 
 x2 
 x3 
 x4 
 x5 
 ;function that returns a closure 
 ;closures seem to be the way to initialize objects with state in scheme 
 (define (r) 
   (let ((seed 0)) 
     (define (dispatch m) 
       (cond ((eq? m 'reset) (lambda (x)(set! seed x))) 
             ((eq? m 'generate) (begin (set! seed (rand-update seed)) 
                                       seed)) 
             (else error "invalid operation"))) 
     dispatch)) 
 ;define rand in terms of r and the closure it returns 
 (define rand (r)) 
 ;test that rand works first with no args assuming 0 as seed 
 (rand 'generate) 
 (rand 'generate) 
 (rand 'generate) 
 ;test that pattern reoccurs 
 ((rand 'reset) 0) 
 (rand 'generate) 
 (rand 'generate) 
 (rand 'generate) 
 ;test the rand works using a new seed 
 ((rand 'reset) 42) 
 (rand 'generate) 
 (rand 'generate) 
 (rand 'generate) 
 ;test the pattern reoccurs 
 ((rand 'reset) 42) 
 (rand 'generate) 
 (rand 'generate) 
 (rand 'generate)