#lang racket #| (define (f x) (letrec ((even? (lambda (n) (if (= n 0) #t (odd? (- n 1))))) (odd? (lambda (n) (if (= n 1) #t (even? (- n 1)))))) )) (letrec ...) is transformed into: (let ((even? '*unassigned*) (odd? '*unassigned*)) (set! even? (lambda (n) (if (= n 0) ... ...))) (set! odd? (lambda (n) ...)) ) |# #| letrec is of the form: (letrec (( ) ... ( )) ) |# (define (tagged-list? expr tag) (or (pair? expr) (eq? (car expr) tag))) (define (letrec? expr) (tagged-list? expr 'letrec)) (define (letrec-variables expr) (let ((p (car (cdr expr)))) (map car p))) (define (letrec-values expr) (let ((p (car (cdr expr)))) (map cadr p))) (define (letrec->let expr) (if (not (letrec? expr)) (error "not a letrec expression -- LETREC") (let ((vars (letrec-variables expr)) (vals (letrec-values expr)) (body (cdr (cdr expr)))) (cons 'let (cons (map (lambda (var) (list var ''*unassigned*)) vars) (append (map (lambda (var val) (list 'set! var val)) vars vals) body)))))) #| b. In the case where we use lecrec, this gets transformed into let. So, when we call (f 5) a new frame is formed with even? and odd? assigned to '*unassigned. Then these are set to the lambda expressions belonging to even? and odd?. When we use a let in the place of letrec, a frame gets created with even? and odd? assigned to the lambda expressions. Then the body of the let expression (i.e. ) is wrapped in a lambda which takes as parameters, even? and odd? is called with the lambda expressions corresponding to even? and odd?. i.e. ((lambda (e? o?) ) (lambda (n) (...reference to o?..)) (lambda (n) (.reference to e?... ))) So, a frame gets created which assigns e? and o? to the corresponding lambdas. The enclosing environment for it, does not have e? or o? defined. So, these definitions When we draw the environment, the two lambdas passed as parameters do not see each other as their environment is the enclosing env of t. so they are undefined. When the body is evaluated, then these will generate error for undefined references. |#