sicp-ex-4.20



<< Previous exercise (4.19) | Index | Next exercise (4.21) >>


meteorgan

  
  
  
 ;; a 
 ;; letrec expression 
 (define (letrec? expr) (tagged-list? expr 'letrec)) 
 (define (letrec-inits expr) (cadr expr)) 
 (define (letrec-body expr) (cddr expr)) 
 (define (declare-variables expr) 
         (map (lambda (x) (list (car x) '*unassigned*)) (letrec-inits expr))) 
 (define (set-variables expr) 
         (map (lambda (x) (list 'set! (car x) (cadr x))) (letrec-inits expr))) 
 (define (letrec->let expr) 
         (list 'let (declare-variables expr)  
                (make-begin (append (set-variables expr) (letrec-body expr))))) 

leafac

 ;; The lambda in `let' is evaluated in the context of the enclosing environment, 
 ;; in which the bindings of the lambda itself are not in place. 
  
 ;; The trick of encoding `letrec' is that we first establish the bindings, and 
 ;; then define the lambdas in an environment where the bindings are there, so 
 ;; the recursive call can succeed. 
  
 ;; The following snippets illustrate the difference: 
  
 (let ((fact <fact-body>)) 
   <let-body>) 
  
 ;; is encoded by 
  
 ((lambda (fact) 
    <let-body>) 
  <fact-body>) 
  
 ;; such that `<fact-body>' can't refer to `fact'. While: 
  
 (letrec ((fact <fact-body>)) 
   <let-body>) 
  
 ;; is encoded by 
  
 ((lambda (fact) 
    (set! fact <fact-body>) 
    <fact-body>) 
  '*unassigned*) 
  
 ;; note that in the context of `<fact-body>', the variable `fact' itself is 
 ;; bound.