140 likes | 149 Views
6001 structure & interpretation of computer programs recitation 15/ november 14, 1997. topics. interpreters meta-linguistic abstraction eval and apply the environment model in code. puzzle for student presentation. build a “shell” with history that works like this: (define m (mk-shell))
E N D
6001structure & interpretation of computer programsrecitation 15/ november 14, 1997
topics • interpreters • meta-linguistic abstraction • eval and apply • the environment model in code
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!
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
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?
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 subexpressionsto 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!)
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 itthe 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)
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
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
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)
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 v1if v1 is false, the value is v1, else continueif all vi are true, value is vn • code • (define evand (lambda (clauses env) • (cond ((null? (cdr clauses)) (mc-eval (car clauses) env)) • ((mc-eval (car clauses) env) (evand (cdr clauses) env)) (else #f)))
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))))
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
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