#lang plait (define-type Exp [numE (n : Number)] [plusE (left : Exp) (right : Exp)] [timesE (left : Exp) (right : Exp)] [lamE (var : Symbol) (body : Exp)] [appE (fun : Exp) (arg : Exp)] [varE (name : Symbol)] [let1E (var : Symbol) (value : Exp) (body : Exp)]) (define (parse s) (local [(define (sx n) (list-ref (s-exp->list s) n)) (define (px n) (parse (sx n))) (define (? pat) (s-exp-match? pat s))] (cond [(? `SYMBOL) (varE (s-exp->symbol s))] [(? `NUMBER) (numE (s-exp->number s))] [(? `(+ ANY ANY)) (plusE (px 1) (px 2))] [(? `(* ANY ANY)) (timesE (px 1) (px 2))] [(? `(let1 (SYMBOL ANY) ANY)) (let* ([def (sx 1)] [parts (s-exp->list def)] [var (s-exp->symbol (list-ref parts 0))] [val (parse (list-ref parts 1))] [body (px 2)]) (let1E var val body))] [(? `(lam SYMBOL ANY)) (lamE (s-exp->symbol (sx 1)) (px 2))] [(? `(ANY ANY)) (appE (px 0) (px 1))] [else (error 'parse (to-string s))]))) (define-type Value [numV (the-number : Number)] [boolV (the-boolean : Boolean)] [funV (var : Symbol) (body : Exp)]) (define (num-op op expr1 expr2) (local [(define (unwrap v) (type-case Value v [(numV n) n] [else (error 'num-op "NaN")]))] (numV (op (unwrap expr1) (unwrap expr2))))) (define-type-alias Env (Hashof Symbol Value)) (define mt-env (hash empty)) ;; "empty environment" (define (extend old-env new-name value) (hash-set old-env new-name value)) (define (lookup (s : Symbol) (n : Env)) (type-case (Optionof Value) (hash-ref n s) [(none) (error s "not bound")] [(some v) v])) (interp : (Exp Env -> Value)) (define (interp e nv) (type-case Exp e [(numE n) (numV n)] [(varE s) (lookup s nv)] [(plusE l r) (num-op + (interp l nv) (interp r nv))] [(timesE l r) (num-op * (interp l nv) (interp r nv))] [(lamE v b) (funV v b)] [(appE f a) (let ([fv (interp f nv)] [av (interp a nv)]) (type-case Value fv [(funV v b) (interp b (extend nv v av))] [else (error 'app "not a function")]))] [(let1E var val body) (let ([new-env (extend nv var (interp val nv))]) (interp body new-env))])) (run : (S-Exp -> Value)) (define (run s) (interp (parse s) mt-env)) (test (run `{let1 {f {lam x {+ x 1}}} {f 8}}) (numV 9)) (test (run `{let1 {y 1} {let1 {f {lam x {+ x y}}} {f 8}}}) (numV 9)) (test (run `{let1 {y 1} {let1 {f {lam x {+ x y}}} {let1 {y 2} {f 8}}}}) (numV 9))