Chapter 4, Metalinguistic Abstraction

Exercise 4.20


(a)

Code is not difficult after doing so exercises. The main part to understand is what Louis pointed out in part(b)

Here goes the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(define (letrec? exp) (tagged-list? exp 'letrec))

(define (letrec-vardefs exp) (cadr exp))

(define (letrec-body exp) (cddr exp))

(define (letrec->let exp)
  (define rs
	(fold-right (lambda(new rem)
				  (cons (cons (list (car new) ''*unassigned*) (car rem))
						(cons (list 'set! (car new) (cadr new)) (cdr rem))))
				(cons '() '())
				(letrec-vardefs exp)))
  (make-let (car rs) (append (cdr rs) (letrec-body exp))))

Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
;;; M-Eval input:
(define (f x)
  (letrec ((even?
            (lambda (n)
              (if (= n 0)
                  true
                  (odd? (- n 1)))))
           (odd?
            (lambda (n)
              (if (= n 0)
                  false
                  (even? (- n 1))))))
    (even? x)))

;;; M-Eval value:
metacircular-evaluator-loaded

;;; M-Eval input:

;;; M-Eval value:
ok

;;; M-Eval input:
(f 5)

;;; M-Eval value:
#f

;;; M-Eval input:
(f 6)

;;; M-Eval value:
#t

;;; M-Eval input:
(f 0)

;;; M-Eval value:
#t

;;; M-Eval input:
(f 1)

;;; M-Eval value:
#f

(b)

If we simply substitute let with letrec it won’t work.

The main thing to see is that variables even? and odd? are bound to the frame created by let expression. Also recall that let is nothing but a lambda definition and invocation. The invocation of lambda evaluates the arguments of let in the environment where let is defined. Thus even? and odd? are not yet binded!

Now, when we invoke even?, we start evaluating the (lambda (n) (if (= n 0) true (odd? (- n 1)))). This lambda do not get evaluated inside the generated lambda(generated for let) environment but in the environment where ‘let’ is defined. But in that environment even? and odd? are not available!

Thus odd? won’t be found and it will report error. Eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
;;; M-Eval input:
(define (f x)
  (let ((even?
            (lambda (n)
              (if (= n 0)
                  true
                  (odd? (- n 1)))))
           (odd?
            (lambda (n)
              (if (= n 0)
                  false
                  (even? (- n 1))))))
    (even? x)))

;;; M-Eval value:
ok

;;; M-Eval input:
(f 5)
;Unbound variable odd?