#lang plait (define-type-alias Env (Hashof Symbol Value)) (define mt-env (hash empty)) ;; "empty environment" (define-type Exp [numE (n : Number)] [plusE (left : Exp) (right : Exp)] [timesE (left : Exp) (right : Exp)] [varE (name : Symbol)] ;; new [let1E (var : Symbol) ;; new (value : Exp) (body : Exp)]) (define-type-alias Value Number) (define (lookup (s : Symbol) (n : Env)) (type-case (Optionof Value) (hash-ref n s) [(none) (error s "not bound")] [(some v) v])) (define (extend old-env new-name value) (hash-set old-env new-name value)) (interp : (Exp Env -> Value)) (define (interp e nv) (type-case Exp e [(numE n) n] [(varE s) (lookup s nv)] [(plusE l r) (+ (interp l nv) (interp r nv))] [(timesE l r) (* (interp l nv) (interp r nv))] [(let1E var val body) (let ([new-env (extend nv var (interp val nv))]) (interp body new-env))])) (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))] [else (error 'parse (to-string s))]))) (run : (S-Exp -> Value)) (define (run s) (interp (parse s) mt-env)) (test (run `{let1 {x 1} {+ x x}} ) 2) (test (run `{let1 {x 1} {let1 {y 2} {+ x y}}}) 3) (test (run `{let1 {x 1} {let1 {y 2} {let1 {x 3} {+ x y}}}}) 5) (test (run `{let1 {x 1} {+ x {let1 {x 2} x}}}) 3)