;; The first three lines of this file were inserted by DrScheme. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "reader.ss" "plai" "lang") ;; An arithmetic interpreter that uses a typed parse tree to reduce implementation errors. ;; ;; Morgan McGuire morgan@cs.williams.edu ; define-type creates a series of related new types. Here, expr is the base type. ; (This is similar to a series of define-struct statements, except that to uses contracts ; to check type signatures and names the constructor after the type rather than calling it ; "make-type".) (define-type expr ; Each clause defines an additional type. This one defines num, which has one part, ; n, that is a Scheme number. This clause creates num? and num-n (and set-num-n!, but ; we won't use that one). (num (n number?)) (add (lhs expr?) (rhs expr?)) (sub (lhs expr?) (rhs expr?))) ; We write a regular Scheme procedure that accepts a Scheme list and converts it ; into a calc expression. (define (parse e) (cond ; If the expression is a number literal, make a calc number: ((number? e) (num e)) ; If the expression looks like ( ... ), choose the type ; based on what is first. ((list? e) (case (first e) ; Begins with "+": create an addition expression: ((+) (add (parse (second e)) (parse (third e)))) ; Begins with "-": create a subtraction expression: ((-) (sub (parse (second e)) (parse (third e)))) )))) ; The calc interpreter using the types defined above. Note that ; this is the same code as calc-1; we changed only the implementation ; of the num, add, and sub types. (define (calc-2 e) (cond [(num? e) (let ([n (num-n e)]) n)] [(add? e) (let ([lhs (add-lhs e)] [rhs (add-rhs e)]) (+ (calc-2 lhs) (calc-2 rhs)))] [(sub? e) (let ([lhs (sub-lhs e)] [rhs (sub-rhs e)]) (- (calc-2 lhs) (calc-2 rhs)))])) ; The calc interpreter from the textbook (more or less). This is our calc-2 interpreter ; re-written using the type-case special form to reduce some of the boilerplate. (define (calc-3 e) ; type-case takes a type (here, expr) and a value (here a calc expression e) of ; that type, and then evaluates the one of the following clauses that describes e (type-case expr e ; If e is a num, extract the underlying Scheme number and return it (num (n) n) (add (lhs rhs) (+ (calc-3 lhs) (calc-3 rhs))) (sub (lhs rhs) (+ (calc-3 lhs) (calc-3 rhs))))) ;; Example: (calc-3 (parse '(+ 1 2)))