Skip to content

Commit 31689b1

Browse files
committed
SICP instructor's manual metacircular evaluator
1 parent cca48f0 commit 31689b1

File tree

3 files changed

+71
-8
lines changed

3 files changed

+71
-8
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Concrete Metacircular Evaluator
2+
3+
Code adapted from the "evaluator with concrete syntax" listed on pages 121-122
4+
of the "Instructor's Manual to accompany Structure and Interpretation of
5+
Computer Programs" by Julie Sussman with Harold Abelson and Gerald Jay Sussman.
6+
7+
Changes:
8+
9+
* function names changed to ALL-CAPS to avoid confusion with
10+
functions provided by Racket;
11+
* parameters named `env` renamed to `environ` to avoid confusion with `exp`;
12+
* use of `#t`, `#f` instead of `true`, `false`;
13+
* APPLY rewritten to avoid the need for `primitive-procedure?`;
14+
the corresponding function in Racket is `primitive?` but it is not
15+
useful to us because `(primitive? +)` returns `#f`, so we can't use it
16+
to distinguish user-defined procedures from the built-ins.
17+
18+
Tested in Racket 8.3.
19+

references/sicp/instructors-manual/concrete-test.rkt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,32 @@
1414

1515
(check-exn (regexp "Unbound variable 'x") (lambda ()
1616
(LOOKUP-VARIABLE-VALUE 'x '())))
17-
; WIP:
17+
1818
(check-equal? (LOOKUP-VARIABLE-VALUE 'x '(([x . 8]))) 8)
1919

2020
(check-equal? (MAKE-FRAME '(a) '(1)) '([a . 1]) "Smalest frame")
2121

2222
(check-equal? (EVAL 1 '()) 1)
23+
(check-equal? (EVAL '(QUOTE symbol) '()) 'symbol)
24+
(check-equal? (EVAL '(QUOTE (1 2 3)) '()) '(1 2 3))
2325
(check-equal? (EVAL 'x (EXTEND-ENVIRONMENT '(x) '(8) '())) 8)
2426
(check-equal? (EVAL '(+ 3 4) (MAKE-BUILTINS)) 7)
25-
(check-equal? (EVAL '(+ (* 3 4) (* 5 6)) (MAKE-BUILTINS)) 42)
27+
(check-equal? (EVAL '(+ (* 3 4) (* 5 6)) (MAKE-BUILTINS)) 42)
28+
(check-equal? (EVAL '((LAMBDA (x) (* x x)) 111) (MAKE-BUILTINS)) 12321)
29+
(check-equal? (EVAL '(((LAMBDA (x)
30+
(LAMBDA (y) (+ x y)))
31+
3)
32+
4)
33+
(MAKE-BUILTINS)) 7)
34+
35+
(check-equal? (EVAL '((LAMBDA (x y)
36+
((LAMBDA (y) (+ x y))
37+
(* x y)))
38+
3 4)
39+
(MAKE-BUILTINS)) 15)
40+
41+
(check-equal? (EVAL '((LAMBDA (x) (IF (< x 0) (- 0 x) x)) 2)
42+
(MAKE-BUILTINS)) 2)
43+
44+
(check-equal? (EVAL '((LAMBDA (x) (IF (< x 0) (- 0 x) x)) -3)
45+
(MAKE-BUILTINS)) 3)

references/sicp/instructors-manual/concrete.rkt

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,45 @@
1111

1212
(define (EVAL exp environ)
1313
;; dispatch on expression type
14-
(cond [(number? exp) exp] ; self-evaluating
15-
[(symbol? exp)
14+
(cond [(number? exp) exp] ; self-evaluating
15+
[(symbol? exp) ; variable?
1616
(LOOKUP-VARIABLE-VALUE exp environ)]
17+
[(eq? (car exp) 'QUOTE) (cadr exp)] ; quoted?
18+
;; rule for procedure objects in the environment model
19+
[(eq? (car exp) 'LAMBDA) ; lambda?
20+
(list 'procedure ; make-procedure
21+
(cadr exp) ; lambda-parameters
22+
(caddr exp) ; lambda-body
23+
environ)]
24+
[(eq? (car exp) 'IF) ; if?
25+
(EVAL-IF exp environ)]
1726
[else
18-
(apply (EVAL (car exp) environ) ; operator
19-
(LIST-OF-VALUES (cdr exp) ; operands
27+
(APPLY (EVAL (car exp) environ) ; operator
28+
(LIST-OF-VALUES (cdr exp) ; operands
2029
environ))]))
2130

31+
(define (APPLY procedure arguments)
32+
;; dispatch on procedure type
33+
(cond [(and (list? procedure) (eq? (car procedure) 'procedure)) ; compoud-procedure?
34+
(EVAL
35+
(caddr procedure) ; procedure-body
36+
(EXTEND-ENVIRONMENT
37+
(cadr procedure) ; procedure-parameters
38+
arguments
39+
(cadddr procedure)))] ; procedure-environment
40+
[else (apply procedure arguments)])) ; (apply ...) from host interpreter
2241

2342
(define (LIST-OF-VALUES exps environ)
2443
(if (null? exps)
2544
'()
2645
(cons (EVAL (car exps) environ)
2746
(LIST-OF-VALUES (cdr exps) environ))))
2847

48+
(define (EVAL-IF exp environ)
49+
(if (EVAL (cadr exp) environ) ; if-predicate
50+
(EVAL (caddr exp) environ) ; if-consequent
51+
(EVAL (cadddr exp) environ))) ; if-alternative
52+
2953
(define (EXTEND-ENVIRONMENT vars values base-environ)
3054
(cons (MAKE-FRAME vars values) base-environ))
3155

@@ -52,8 +76,8 @@
5276

5377
(define (MAKE-BUILTINS)
5478
(EXTEND-ENVIRONMENT
55-
'(+ - * /)
56-
(list + - * /)
79+
'(+ - * / <)
80+
(list + - * / <)
5781
'()))
5882

5983
; Needed to support rackunit tests in concrete-test.rkt.

0 commit comments

Comments
 (0)