6001 structure & interpretation of computer programs recitation 15/ november 14, 1997
topics interpreters meta-linguistic abstraction eval and apply the environment model in code 5/16/2019 daniel jackson
puzzle for student presentation build a “shell” with history that works like this: (define m (mk-shell)) (m ‘execute p) ; executes the procedure p and sets p to be the current proc (m ‘back) ; sets the current proc back one (m ‘forward) ; sets the current proc forward one (m ‘run) ; executes the current proc hint use the circular buffer we designed last time! 5/16/2019 daniel jackson
meta-linguistic abstraction ways to build a big system break it into smaller pieces invent a new language why invent a new language? new way to think about the system tailored to the problem at hand code can be much more succinct examples the Unix shell Mathematica Excel spreadsheet macros 5/16/2019 daniel jackson
a very simple interpreter an arithmetic evaluator code (define (arith-eval exp) (cond ((pair? exp) (arith-apply (cadr exp) (arith-eval (car exp)) (arith-eval (caddr exp)))) (else exp))) (define (arith-apply op x y) (cond ((eq? op ‘*) (* x y)) ((eq? op ‘+) (+ x y))) sample run (define e ‘(2 * (3 + 4))) (arith-eval e) ==> 14 question what will arith-apply look like if there are lots of primitive ops? how could it be coded more elegantly? 5/16/2019 daniel jackson
essential idea: recursive evaluation even in this trivial example we have the fundamental structure of a LISP interpreter recursive evaluation recall our rule for evaluation to evaluate a combination expression evaluate the subexpressions, and apply the value of the operator subexpressions to the values of the operand subexpressions a primitive expression – a number – evaluates to itself and in the better version of arith-apply namely (define (arith-apply op x y) (apply (lookup op op-table) (list x y))) we have the notion of an environment (but a crude one: it’s fixed!) 5/16/2019 daniel jackson
environments what does Scheme have that our arithmetic expression language doesn’t? procedures variables and environments these are interwoven because environments are needed to execute procedures basic idea of parameter binding: evaluate the body in an environment that has the parameters bound to the argument values lexical scoping recall that in Scheme a procedure carries with it the environment in which it was created and the environment in which its body is evaluated is an extension of this environment this is not so essential (but it’s very nice) 5/16/2019 daniel jackson
an evaluator for scheme the code (define mc-eval (lambda (exp env) (cond ((number? exp) exp) ;base-case ((symbol? exp) (lookup exp env)) ;base case ((eq? (car exp) 'quote) (car (cdr exp))) ;special forms ((eq? (car exp) 'cond) (evcond (cdr exp) env)) ((eq? (car exp) 'begin) (evseq (cdr exp) env)) ((eq? (car exp) 'lambda) (list 'proc (cdr exp) env)) ((eq? (car exp) 'define) (evdefine (cdr exp) env)) (else (mc-apply (mc-eval (car exp) env) (evlist (cdr exp) env)))))) features to look out for the recursive structure: where are the base cases? the call to mc-apply how procedures are represented how the environment is passed through 5/16/2019 daniel jackson
an applier for scheme the code (define mc-apply (lambda (fun args) (cond ((not (pair? fun)) (apply fun args)) ;ground out ((eq? (car fun) 'proc) (mc-eval (car (cdr (car (cdr fun)))) ; procedure body (bind (car (car (cdr fun))) ;formal params args ;supplied args (car (cdr (cdr fun)))))) ;saved env (else (error '"Unknown function"))))) features to look out for the recursive structure: where are the base cases? the call to mc-eval how procedures are applied how the environment is passed through 5/16/2019 daniel jackson
playing with the interpreter evaluate these expressions 1 (+ 3 4) (+ (* 3 4) (* 5 6)) ((lambda (x) (* x x)) 3) ((lambda (x) (lambda (y) (+ x y))) 3) 4) 5/16/2019 daniel jackson
filling in the details: sequences how sequences are evaluated (define evseq (lambda (clauses env) (cond ((null? (cdr clauses)) (mc-eval (car clauses) env)) (else (mc-eval (car clauses) env) (evseq (cdr clauses) env))))) can you add the and special form? definition: to evaluate (and e1 e2 … en) evaluate e1 to v1 if v1 is false, the value is v1, else continue if all vi are true, value is vn code (define evand (lambda (clauses env) ((mc-eval (car clauses) env) (evand (cdr clauses) env)) (else #f))) 5/16/2019 daniel jackson
filling in the details: define code (define evdefine (lambda (body env) ;mutate the first frame (begin (set-cdr! (car env) (cons (cons (car body) (mc-eval (car (cdr body)) env)) (cdr (car env)))) (car body)))) 5/16/2019 daniel jackson
meta-circularity this interpreter is a scheme interpreter written in scheme! can be viewed as a semantics: we can read to understand how scheme evaluates expressions figure out where these features are evident in the code applicative order evaluation: all the arguments of a procedure are evaluated before the call lexical scoping shadowing of variables 5/16/2019 daniel jackson
puzzle for student presentation implement an evaluator for a simple assignment language takes a list of statements a statement is either an assignment (var := expr) or a print statement (print expr) hint use arith-eval modified to include a simple environment 5/16/2019 daniel jackson