#lang plai (print-only-errors) (define-type WAE [num (n number?)] [add (lhs WAE?) (rhs WAE?)] [sub (lhs WAE?) (rhs WAE?)] [id (name symbol?)] [with (name symbol?) (named-expr WAE?) (body WAE?)]) ;; interp : WAE? -> number? (define (interp an-ae) (type-case WAE an-ae [num (n) n] [add (l r) (+ (interp l) (interp r))] [sub (l r) (- (interp l) (interp r))] [id (name) (error 'interp "free identifier")] [with (name named-expr body) (interp (subst body name (interp named-expr)))])) ;; subst : WAE? symbol? number? -> WAE? (define (subst a-wae name value) (type-case WAE a-wae [num (n) a-wae] [add (l r) (add (subst l name value) (subst r name value))] [sub (l r) (sub (subst l name value) (subst r name value))] [id (name2) (if (equal? name name2) (num value) a-wae)] [with (name2 named-expr body) (with name2 (subst named-expr name value) (if (equal? name name2) body (subst body name value)))])) (test (subst (id 'x) 'x 10) (num 10)) (test (subst (id 'y) 'x 10) (id 'y)) (test (subst (add (id 'x) (id 'y)) 'x 10) (add (num 10) (id 'y))) (test (subst (add (id 'x) (id 'y)) 'y 10) (add (id 'x) (num 10))) (test (subst (with 'y (num 10) (id 'x)) 'x 10) (with 'y (num 10) (num 10))) (test (subst (with 'x (num 4) (id 'x)) 'x 10) (with 'x (num 4) (id 'x))) (test (subst (with 'x (id 'x) (num 5)) 'x 10) (with 'x (num 10) (num 5))) ;; 5 (test (interp (num 5)) 5) ;; {+ 5 2} (test (interp (add (num 5) (num 2))) 7) ;; {{+ 3 4} + {- 2 5}} ;; WRONG ;; {- 3 {+ 4 5}} (test (interp (sub (num 3) (add (num 4) (num 5)))) -6) ; x (test/exn (interp (id 'x)) "free identifier") ;; {with {x 3} x} (test (interp (with 'x (num 3) (id 'x))) 3) (test (interp (with 'x (add (num 1) (num 2)) (id 'x))) 3) (test (interp (with 'x (num 3) (with 'x (num 2) (id 'x)))) 2) (test (interp (with 'y (num 3) (with 'x (num 2) (add (id 'x) (id 'y))))) 5) ;; {with {x x} {+ x 1}} (test/exn (interp (with 'x (id 'x) (add (id 'x) (num 1)))) "free identifier")