1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as...

33
1 The metacircular evaluator

Transcript of 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as...

Page 1: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

1

The metacircular evaluator

Page 2: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

2

2. Names

• Extend the calculator to store intermediate results as named values

(define x (+ 4 5)) store result as x

(+ x 2) use that result

• Store bindings between names and values in a table

Page 3: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

3

2. Names 

(define (define? exp) (tag-check exp 'define)) (define (eval exp) (cond ((number? exp) exp) ((symbol? exp) (lookup exp)) ((sum? exp) (eval-sum exp)) ((define? exp) (eval-define exp)) (else (error "unknown expression " exp)))) (define environment (make-frame nil nil)) (define (lookup name) (lookup-variable-value name environment)) (define (eval-define exp) (let ((name (cadr exp)) (defined-to-be (eval (caddr exp)))) (add-binding-to-frame! name defined-to-be environment) ‘undefined))

  

Page 4: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

4

(define (make-frame variables values) (cons variables values))

(define (lookup-variable-value var frame)

(define (scan vars vals) (cond ((null? vars) (error "Unbound variable" var))

((eq? var (car vars) (car vals)) (else (scan (cdr vars) (cdr vals)))))

(let ((vars (car frame)) (vals (cdr frame))) (scan vars vals)))

(define (add-binding-to-frame! var val frame) (set-car! frame (cons var (car frame))) (set-cdr! frame (cons val (cdr frame))))

Page 5: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

5

The environment is a single frame

list ofvalues

list ofvariables

frame

x y 4 5

Page 6: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

6

Evaluation of

(eval '(define x (+ 4 5)))

(eval '(+ 4 5))

(eval 4) ==> 4

(eval 5) ==> 5

==> 9 names values x 9==> undefined

(eval '(+ x 2))

(eval 'x) ==> 9

(eval 2) ==> 2

==> 11

(define x (+ 4 5))(+ x 2)

Page 7: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

7

2. Things to observe

• Use scheme function symbol? to check for a name• the reader converts sequences of characters like "x" to

symbols in the parse tree

• Can use any implementation of the environment, in particular we could use put and get from previous lectures.

•eval-define recursively calls eval on the second subtree but not on the first one

•eval-define returns a special undefined value

Page 8: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

8

3. Conditionals and if

• Extend the calculator to handle conditionals and if:

(if (> y 6) (+ y 2) 15)

•> an operation that returns a boolean•if an operation that evaluates the first subexp,

checks if value is true or false

Page 9: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

9

3. Conditionals and if 

(define (greater? exp) (tag-check exp ’>))(define (if? exp) (tag-check exp 'if)) (define (eval exp) (cond ((number? exp) exp) ((symbol? exp) (lookup exp)) ((sum? exp) (eval-sum exp)) ((greater? exp) (eval-greater exp)) ((define? exp) (eval-define exp)) ((if? exp) (eval-if exp)) (else (error "unknown expression " exp)))) (define (eval-greater exp) (> (eval (cadr exp)) (eval (caddr exp))))  

Page 10: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

10

(define (eval-if exp) (if (true? (eval (if-predicate exp))) (eval (if-consequent exp)) (eval (if-alternative exp))))

(define (if-predicate exp) (cadr exp))(define (if-consequent exp) (caddr exp))(define (if-alternative exp) (if (not (null? (cdddr exp))) (cadddr exp) 'false))

(define (true? x) (not (eq? x #f)))

(define (false? x) (eq? x #f)) (eval '(define y 9))(eval '(if (> y 6) (+ y 2) 15)) 

Page 11: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

11

We are just walking through a tree …

(eval )

6y>

if

6y> 2y+

15

Then (eval ) or (eval 15 )

2y>

Page 12: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

12

Evaluation of

(eval '(if (> y 6) (+ y 2) 15))

(eval '(> y 6))

(eval 'y) ==> 9

(eval 6) ==> 6

==> #t

(eval '(+ y 2))

(eval 'y) ==> 9

(eval 2) ==> 2

==> 11

==> 11

Page 13: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

13

3. Things to observe

•eval-greater is just like eval-sum from page 1• recursively call eval on both argument expressions• call scheme > to compute value

•eval-if does not call eval on all argument expressions:• call eval on the predicate

• call eval on the consequent or on the alternative but not both

Page 14: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

14

4. Store operators in the environment

• Want to add lots of operators but keep eval short

• Operations like + and > are similar• evaluate all the argument subexpressions• perform the operation on the resulting values

• Call this standard pattern an application• Implement a single case in eval for all applications

• Approach:•eval the first subexpression of an application• put a name in the environment for each operation• value of that name is an procedure• apply the procedure to the operands

Page 15: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

15

4. Store procedures in the environment 

(define (application? e) (pair? e)) (define (eval exp) (cond ((number? exp) exp) ((symbol? exp) (lookup exp)) ((define? exp) (eval-define exp)) ((if? exp) (eval-if exp)) ((application? exp) (apply (eval (car exp)) (map eval (cdr exp)))) (else (error "unknown expression " exp)))) ;; rename scheme’s apply so we can reuse the name(define scheme-apply apply) (define (apply procedure arguments) (if (primitive-procedure? procedure) (apply-primitive-procedure procedure arguments) (error "operator not a procedure: " procedure)))

(define (apply-primitive-procedure proc args) (scheme-apply (primitive-implementation proc) args))

Page 16: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

16

4. Store procedures in the environment 

 (define prim-tag 'primitive)(define (make-primitive scheme-proc)(list prim-tag scheme-proc))(define (primitive-procedure? e) (tag-check e prim-tag))(define (primitive-implementation prim) (cadr prim)) (define environment (make-frame nil nil))(add-binding-to-frame! environment ’+ (make-primitive +))(add-binding-to-frame! environment ’> (make-primitive >))(add-binding-to-frame! environment 'true #t) (eval '(define z 9))(eval '(+ 9 6)) (eval '(if true 10 15))  

Page 17: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

17

The Environment after first green line

names values z 9true #t>+

symbolprimitive

schemeprocedure

>symbol

primitive

schemeprocedure

+

Page 18: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

18

Evaluation of (+ 9 6)

(eval '(+ 9 6))(apply (eval +) (map eval '(9 6)))(apply '(primitive #[add]) (list (eval 9) (eval 6))

(apply '(primitive #[add]) '(9 6))(scheme-apply (primitive-implementation '(primitive #[add])) '(9 6))

(scheme-apply #[add] '(9 6))15

Page 19: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

19

Evaluation of (if true 10 15)

(eval '(if true 10 15))(eval-if '(if true 10 15))(if (true? (eval 'true)) ...)(if (true? (lookup 'true))) ...)(if (true? #t) ...)(eval 10)10

Apply is never called!

Page 20: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

20

4. Things to observe

• applications must be last case in eval • no tag check

• applications evaluate all subexpressions• expressions that need special handling, like if,

gets their own case in eval

Page 21: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

21

5. Environment as explicit parameter

• change from(eval '(+ 6 4))

to(eval '(+ 6 4) environment)

• all procedures that call eval have extra argument•lookup and define use environment from argument

• No other change from evaluator 4

Page 22: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

22

5. Environment as explicit parameter ;This change is boring! Exactly the same functionality as #4. 

(define (eval exp env) (cond ((number? exp) exp) ((symbol? exp) (lookup exp env)) ((define? exp) (eval-define exp env)) ((if? exp) (eval-if exp env)) ((application? exp) (apply (eval (car exp) env) (map (lambda (e) (eval e env)) (cdr exp)))) (else (error "unknown expression " exp))))

(define (lookup name env) (lookup-variable-value name env)) (define (eval-define exp env) (let ((name (cadr exp)) (defined-to-be (eval (caddr exp) env))) (add-binding-to-frame! name defined-to-be env) ‘undefined)) 

Page 23: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

23

5. Environment as explicit parameter 

(define (eval-if exp env) (if (true? (eval (if-predicate exp) env)) (eval (if-consequent exp) env) (eval (if-alternative exp) env)))

Page 24: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

24

6. Defining new procedures

• Want to add new procedures• For example, a scheme program:

(define twice (lambda (x) (+ x x)))(twice 4)

• Strategy:• Add a case for lambda to eval

– the value of lambda is a compound procedure• Extend apply to handle compound procedures• Implement environment model

Page 25: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

25

6. Defining new procedures 

(define (lambda? e) (tag-check e 'lambda)) 

(define (eval exp env) (cond ((number? exp) exp) ((symbol? exp) (lookup exp env)) ((define? exp) (eval-define exp env)) ((if? exp) (eval-if exp env)) ((lambda? exp) (eval-lambda exp env)) ((application? exp) (apply (eval (car exp) env) (map (lambda (e) (eval e env)) (cdr exp)))) (else (error "unknown expression " exp)))) (define (eval-lambda exp env) (make-procedure (lambda-parameters exp) (lambda-body exp) env))

(define (lambda-parameters exp) (cadr exp))(define (lambda-body exp) (cddr exp))

(define (make-procedure parameters body env) (list 'procedure parameters body env))

Page 26: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

26

6. Defining new procedures 

(define (apply procedure arguments) (cond ((primitive-procedure? procedure) (apply-primitive-procedure procedure arguments)) ((compound-procedure? procedure) (eval-sequence (procedure-body procedure) (extend-environment (procedure-parameters procedure) arguments (procedure-env procedure)))) (else (error "Unknown procedure type -- APPLY" procedure)))) 

(define (compound-procedure? exp) (tag-check exp ‘procedure)) (define (procedure-parameters compound) (cadr compound))(define (procedure-body compound) (caddr compound))(define (procedure-env compound) (cadddr compound))

Page 27: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

27

(define (eval-sequence exps env) (cond ((last-exp? exps) (eval (first-exp exps) env)) (else (eval (first-exp exps) env) (eval-sequence (rest-exps exps) env))))

(define (last-exp? seq) (null? (cdr seq)))(define (first-exp seq) (car seq))(define (rest-exps seq) (cdr seq))

Page 28: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

28

How the Environment Works

• Abstractly – in our environment diagrams:

• Concretely – our implementation (as in SICP)

E2 x: 10plus: (procedure ...)

E1

environmentmanipulation

3.

list ofvalues

enclosing-environment

list ofvariables

frame

x plus 10

E2

procedure

Page 29: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

29

Extending the Environment

•(extend-environment '(x y) (list 4 5) E2)

E1

E2 x: 10plus: (procedure ...)

E3 x: 4y: 5

Abstractly

ConcretelyE2

list ofvalues

list ofvariables

frame

x y 4

E3

5

E1

Page 30: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

30

(define (extend-environment vars vals base-env) (if (= (length vars) (length vals)) (cons (make-frame vars vals) base-env) (if (< (length vars) (length vals)) (error "Too many arguments supplied" vars vals) (error "Too few arguments supplied" vars vals))))

Page 31: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

31

"Scanning" the environment

• Look for a variable in the environment...

• Look for a variable in a frame...– loop through the list of vars and list of vals in parallel– detect if the variable is found in the frame

• If not found in frame (out of variables in the frame),look in enclosing environment

Page 32: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

32

(define (lookup-variable-value var env) (define (env-loop env) (define (scan vars vals) (cond ((null? vars) (env-loop (enclosing-environment env))) ((eq? var (car vars)) (car vals)) (else (scan (cdr vars) (cdr vals))))) (if (eq? env the-empty-environment) (error "Unbound variable" var) (let ((frame (first-frame env))) (scan (frame-variables frame) (frame-values frame))))) (env-loop env))

(define (frame-variables frame) (car frame))(define (frame-values frame) (cdr frame))

(define (enclosing-environment env) (cdr env))

Page 33: 1 The metacircular evaluator. 2 2. Names Extend the calculator to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x.

33

(define (define-variable! var val env) (let ((frame (first-frame env))) (define (scan vars vals) (cond ((null? vars) (add-binding-to-frame! var val frame)) ((eq? var (car vars)) (set-car! vals val)) (else (scan (cdr vars) (cdr vals))))) (scan (frame-variables frame) (frame-values frame))))

(define (eval-define exp env) (let ((name (cadr exp)) (defined-to-be (eval (caddr exp) env))) (define-variable! name defined-to-be env) ‘undefined))