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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
 #lang racket
(define (r2 e) (myeval e emptyenv))
(struct closure (args e env) #:transparent)
(define emptyenv '())
(define (extendenv k v env) (cons `(,k . ,v) env))
(define (lookup x env) (match (assq x env) [`(,_ . ,v) v] [_ (error 'varloopup "can't find ~a" x)]))
(define (extendenv* l env) (match l ['() env] [`([,k ,v] . ,rest) (let* ([v (myeval v env)] [newenv (extendenv k v env)]) (extendenv* rest newenv))]))
(define (myeval e env) (match e [(? number? e) e] [(? symbol? e) (lookup e env)] [`(let ,bindings ,body) (let ([newenv (extendenv* bindings env)]) (myeval body newenv))] [`(lambda ,args ,body) (closure args body env)] [`(,op ,x ,y) #:when (member op '(+  * /)) (let ([x (myeval x env)] [y (myeval y env)]) (match op ['+ (+ x y)] [' ( x y)] ['* (* x y)] ['/ (/ x y)]))] [`(,f . ,args) (let ([f (myeval f env)] [argsv (for/list ([x args]) (myeval x env))]) (match f [(closure args body env) (let ([bindings (map list args argsv)]) (myeval body (extendenv* bindings env)))]))]))
(module+ main (require rackunit) (require rackunit/textui) (definesyntaxrule (tests) (list (checkequal? (r2 '3) 3) (checkequal? (r2 '(+ 1 2)) 3) (checkequal? (r2 '( 1 2)) 1) (checkequal? (r2 '(* 1 2)) 2) (checkequal? (r2 '(/ 1 2)) 1/2) (checkequal? (r2 '(* (+ 1 2) (/ 3 4))) 9/4) (checkequal? (r2 '(let ([x 3]) (+ x 3))) 6) (checkequal? (r2 '(lambda (x) (* 2 x))) (closure '(x) '(* 2 x) '())) (checkequal? (r2 '(let ([f (lambda (x) x)]) 3)) 3) (checkequal? (r2 '(let ([f (lambda (x) x)]) (f 3))) 3) (checkequal? (r2 '(let ([x 2] [f (lambda (y) (* x y))]) (f 3))) 6) (checkequal? (r2 '(let ([x 2] [f (lambda (y) (* x y))]) (let ([x 4]) (f 3)))) 6) (checkequal? (r2 '(let ([x 2] [y 5]) (+ x y))) 7) (checkequal? (r2 '(let ([x 2] [f (lambda (x y) (* x y))]) (f x 8))) 16) (checkequal? (r2 '(let ([power (lambda (x) (* x x))]) (power 3))) 9) ))
(void (runtests (testsuite "all" (tests)))) )
