Subt model interpreter Structure of the interpreter Schemeexpression
Subt. model interpreter: Structure of the interpreter <Scheme-expression> Parser <AST> Data structures substitution values • Proc / Primitive-Proc. • Global Environment. Utils A racket lib 1 ASP Core • Op. semantics (evaluation rules) • Special forms Test Derived expressions • ADT per expressions • An abstraction barrier • Used by all evaluators
Subt. model interpreter: The testing mechanism Tests package: Should be run with every modification! The procedure test: • Receives a single expression, e, and an expected value, v. • Returns #t if and only if e evaluates to v. (test (derive-eval ‘(* 3 4)) => ‘(value 12)) The procedure run-tests: • Runs multiple number test expressions (run-tests (test (derive-eval ‘(+ 3 4)) => ‘(value 7)) (test (derive-eval ‘(- 3 4)) => ‘(value -1)) (test (derive-eval ‘(/ 4 2)) => ‘(value 2))) 2
Subt. model interpreter: The core - components Core main-loop: (define applicative-eval (lambda (exp) (cond ((atomic? exp) (eval-atomic exp)) ((special-form? exp) (eval-special-form exp)) ((evaluator-value? exp) ((application? exp) (let ((renamed-exp (rename exp))) (apply-procedure (applicative-eval (operator renamed-exp)) (list-of-values (operands renamed-exp ))))) (else (error 'eval "unknown expression type: ~s" exp))))) applicative -eval (define apply-procedure (lambda (procedure arguments) (cond ((primitive-procedure? procedure) (apply-primitive-procedure arguments)) ((compound-procedure? procedure) (let ((parameters (procedure-parameters procedure)) (body (rename (procedure-body procedure)))) (eval-sequence (substitute body parameters arguments)))) (else (error 'apply "Unknown procedure type: ~s" procedure))))) applyprocedure 3 substitute rename
Subt. model interpreter: The core – components A reminder: Why do we need renaming? The problem: 1. ( (lambda(x) 2. (lambda(y) (y x))) 3. • • (lambda(y) (y (lambda(x) (+ x y)))) (lambda(x) (+ x y)) ) y in line 2 is bound. y in line 3 is free. • The free occurrence of y is now bound by the formal parameter. The solution: consistently rename bound occurrences and their binding instances: 1. ( (lambda(x) 2. (lambda(y 1) (y 1 x))) 3. 4 (lambda(x) (+ x y)) ) (lambda(y 1) (y (lambda(x) (+ x y))))
Subt. model interpreter: The core – special forms Supporting case expressions –syntax: (case ASP <numeric_expression> (<value 0> <consequence 0>) (<value 1> <consequence 1>). . (else <consequence_n>)) Derived expressions Core <special> ica te <special> pr ed OR <lambda> 5 <quote> <if> <case> <exp> Co Or nseq de ue red nc e-e AND. Data structures xp rs: <exp>+
Subt. model interpreter: The core – special forms Supporting case expressions – usage example: (define fib (lambda (n) (case n control (0 0) clauses (1 1) last clause (else (+ (fib (- n 1)) (fib (- n 2))))))) What are the components of a case expressions? ASP Derived expressions Core What are the components of a case-clause? Data structures 6
Subt. model interpreter: The core – special forms Supporting case expressions as a special form Step 1: call the appropriate special evaluation procedure (define eval-special-form (lambda (exp) (cond ((quoted? exp) (make-value exp)) ((lambda? exp) (eval-lambda exp)) ((definition? exp) (eval-definition exp)) ((if? exp) (eval-if exp)) ((begin? exp) (eval-begin exp)) ((case? exp) (eval-case exp))))) ASP Derived expressions Core Step 2: Identify the expression as a special form (define special-form? (lambda (exp) (or (quoted? exp) (lambda? exp) (definition? exp) (if? exp) (begin? exp) (case? exp)))) 7 Data structures
Subt. model interpreter: The core – special forms Supporting case expressions as a special form Step 3: Write the relevant special evaluation procedure Determining the evaluation rule for a case expression: 1. Evaluate the control. 2. Compare its value against compared components by order (assume numerical values). 3. Evaluate the actions of the 1 st clause where the compared value equals the control value. 4. If no such clause exists, evaluate the actions of the else-clause by order. 8 (define fib (lambda (n) (case n (0 0) (1 1) (else (+ (fib (- n 1)) (fib (- n 2)…)
Subt. model interpreter: The core – special forms Supporting case expressions as a special form Step 3: Write the relevant special evaluation procedure (define (eval-case exp) (letrec ((eval-clauses (lambda (control clauses) (cond ((null? clauses) 'unspecified) ((or (case-last-clause? clauses) (= (app-eval (case-compared (case-first-clauses))) control)) (eval-sequence (case-actions (case-first-clauses)))) (else (eval-clauses control ( case-rest-clauses))))))) (eval-clauses (applicative-eval (case-control exp)) (case-clauses exp)))) 9 (define fib (lambda (n) (case n (0 0) (1 1) (else (+ (fib (- n 1)) (fib (- n 2)…)
Subt. model interpreter: The Abstract Syntax Parser (ASP) Example: ADT and implementation for lambda expressions ; Signature: make-lambda(parameters, body) ; Type: [LIST(Symbol)*LIST -> LIST] (define make-lambda (parameters body) (attach-tag (cons parameters body) 'lambda))) ; Signature: lambda-parameters(exp) ; Type: [LIST -> LIST(Symbol)] (define lambda-parameters (lambda (exp) (car (get-content exp)))) ; Signature: lambda-body(exp) ; Type: [LIST -> LIST] (define lambda-body (lambda (exp) (cdr (get-content exp)))) ; Signature: lambda? (exp) ; Type: [T -> Boolean] (define lambda? (lambda (exp) (tagged-by? exp 'lambda))) 10 ASP Derived expressions Core Data structures
Subt. model interpreter: The Abstract Syntax Parser (ASP) ADT for case expressions (including ADT for case-clause): Constructor for case-clause make-case(control case-clauses) Type: [Symbol*LIST -> CASE-Expression] make-case-clause(compared actions) Type: [T*LIST -> CLAUSE-Expression] Predicate Selectors case? (exp) Type: [T -> Boolean] case-actions Case-compared case-first-clause case-rest-clauses Selectors case-control(case-exp) Type: [CASE-Expression -> Symbol] Predicate Case-last-clause? case-clauses(case-exp) Type: [CASE-Expression -> LIST] Usage example (client side): (make-case 'n (list (make-case-clause '0 '(0)) (make-case-clause '1 '(1)) (make-case-clause 'else '(+ (fib (- n 1)) (fib (– n 2)))))) 11
Subt. model interpreter: The Abstract Syntax Parser (ASP) Adding the implementation of the ADT: Co (define make-case nst ruc tor (lambda (control case-clauses) (attach-tag (cons control case-clauses) 'case))) (define case-control (lambda (case-exp) (car (get-content case-exp)))) Se lec tor s (define case-clauses (lambda (case-exp) (cdr (get-content case-exp)))) (define case? (lambda (exp) (tagged-by? exp 'case))) 12 Pre dic a (define make-case-clause (lambda (compared actions) (cons compared actions))) Co nst ruc (define case-compared car) (define case-actions cdr) (define case-first-clause (lambda (clauses) (car clauses))) Sel ect o rs (define case-rest-clauses (lambda (clauses) (cdr clauses))) Pr te tor ed (define case-last-clause? ica te (lambda (clauses) (and (null? (cdr clauses)) (eq? (case-compared (case-first-clauses)) 'else))))
Subt. model interpreter: Derived expressions Example: deriving a case expression (case e (1 (do. Something)) (2 (* e 2)) (else e)) (if (= e 1) (do. Something) (if (= e 2) (* e 2) e)) (let ((ex e)) (if (= ex 1) (do. Something) (if (= ex 2) (* ex 2) ex))) Any problem? 13
Subt. model interpreter: Derived expressions Why? Smaller, simpler core! (let ((x 1)) x) ((lambda(x) x) 1) How? ASP Derive? Shallowderive Identifies the derived expression, calls the appropriate shallow translation procedure: derive Derived expressions Recursively applies shallow-derive Core ((cond? exp) (cond->if exp)) ⁞ ((let? exp) (let->combination exp)) 1. 2. 3. 14 Edit Derive? to consider the new exp as derived. Edit Shallow-derive to call the relevant translation procedure. Add a shallow translation procedure. Data structures
Subt. model interpreter: Derived expressions (define derive (lambda (exp) (if (atomic? exp) exp (let ((derived-exp (let ((mapped-derive-exp (map derive exp))) (if (not (derived? exp)) mapped-derive-exp (shallow-derive mapped-derive-exp))))) (if (equal? exp derived-exp) exp (derived-exp)))))) (define derived? (lambda (exp) (or (cond? exp) (function-definition? exp) (letrec? exp)))) (define shallow-derive (lambda (exp) (cond ((cond? exp) (cond->if exp)) ((function-definition? exp) (function-define->define exp)) ((let? exp) (let->combination exp)) ((letrec? exp) (letrec->let exp)) (else "Unhandled derivision" exp)))) 15
Subt. model interpreter: Data Structures ADT for the procedure data-structure (closure) : ; Signature: make-procedure(parameters, body) ; Type: [LIST(Symbol)*LIST -> LIST] ASP Derived expressions ; Signature: procedure-parameters(exp) ; Type: [LIST -> LIST(Symbol)] ; Signature: lambda-body(exp) ; Type: [LIST -> LIST] ; Signature: Compound-procedure? (exp) ; Type: [T -> Boolean] 16 Core Data structures
Subt. model interpreter: Data Structures The Global Environment: • A substitution between variables and values. (define make-the-global-environment (lambda () (let* ((primitive-procedures (list ‘car car) (list ‘cdr cdr) (list ‘cons) (list ‘null? ) (list ‘+ +) (list ‘* *) (list ‘/ /) (list ‘> >) ; more primitives… )) (prim-variables (map car primitive-procedures)) (prim-values (map (lambda (x) (make-primitive-procedure (cadr x))) primitive-procedures))) (make-sub prim-variables prim-values)) )) 17 ASP Derived expressions Core Data structures
Subt. model interpreter: Data Structures Getting the value of a variable in the GE: • Implemented as a look-up procedure. (define get-value-of-variable (lambda (sub var) (letrec ((lookup (lambda (vars vals) (cond ((or (empty-sub sub) (not (member vars))) (error ‘get-value-of-variable…)) ((eq? var (car vars)) (car vals)) (else (lookup (cdr vars) (cdr vals))))))) (lookup (get-variables sub) (get-values sub))))) ASP Derived expressions Core Data structures 18
Subt. model interpreter: Data Structures The substitution ADT: (define substitute (lambda (expr variables values) (if (evaluator-value? expr) (substitution-application-to-value (make-sub variables values) expr) (substitution-application-to-expr (make-sub variables values) expr)) )) (define substitution-application-to-expr (lambda (sub expr) (cond ((empty-sub? sub) expr) ((or (number? expr) (boolean? expr) (quoted? expr)) expr) (else (let ((vars (get-variables sub)) (values (get-values sub))) (cond ((variable? expr) (if (member expr vars) (get-value-of-variable sub expr (lambda () expr)) ; a list of expressions, lambda, application, cond. (else (map (lambda (e) (substitute e vars values)) expr)))))) )) 19
Subt. model interpreter: Data Structures The substitution ADT: (define substitute (lambda (expr variables values) (if (evaluator-value? expr) (substitution-application-to-value (make-sub variables values) expr) (substitution-application-to-expr (make-sub variables values) expr)) )) (define substitution-application-to-value (lambda (sub val-expr) (let ((vars (get-variables sub)) (values (get-values sub))) (cond ((primitive-procedure? val-expr) ((value? val-expr) (if (atomic? (value-content val-expr)) val-expr (make-value (map (lambda (e) (substitute e vars values)) (value-content val-expr))))) ((compound-procedure? val-expr) (make-procedure (procedure-parameters val-expr) (map (lambda (e) (substitute e vars values)) (procedure-body val-expr)))))) )) 20
- Slides: 20