1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e...

38
1 The metacircular evaluator (Cont.)

Transcript of 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e...

Page 1: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

1

The metacircular evaluator (Cont.)

Page 2: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

2

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 3: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

3

  

(eval '(define twice (lambda (x) (+ x x))) GE)

Page 4: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

4

Implementation of lambda

(eval '(lambda (x) (+ x x)) GE)

(eval-lambda '(lambda (x) (+ x x)) GE)

(make-procedure '(x) ’((+ x x)) GE)

(list ’procedure '(x) ’((+ x x)) GE)

symbolprocedure

symbol+

symbolx

GE

This datastructure isa procedure!

Page 5: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

5

Naming the procedure

(eval '(define twice (lambda (x) (+ x x))) GE)

names values z 9true #t+twice

symbolprimitive

schemeprocedure +

symbolprocedure

symbol+

symbolx

Page 6: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

6

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 7: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

7

(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 8: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

8

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 9: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

9

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 10: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

10

(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 11: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

11

(eval '(twice 4) GE)

Page 12: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

12

Implementation of apply (1)

(eval '(twice 4) GE)

(apply (eval 'twice GE) (map (lambda (e) (eval e GE)) '(4)))

(apply (list 'procedure '(x) ’((+ x x)) GE) '(4))

(eval-seq ’((+ x x)) (extend-environment '(x) '(4) GE))

(eval '(+ x x) E1)

name valuex 4

GE

E1

A

Page 13: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

13

Implementation of apply (2)(eval '(+ x x) E1)

(apply (eval + E1) (map (lambda (e) (eval e E1)) '(x x)))

(apply '(primitive #[add]) (list (eval 'x E1) (eval 'x E1)))

(apply '(primitive #[add]) '(4 4))

(scheme-apply #[add] '(4 4))

8

name valuex 4

GE

E1

A

Page 14: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

14

"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 15: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

15

(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 16: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

16

(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))

Page 17: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

17

The Initial (Global) Environment primitives andinitial env.

4.

(define the-empty-environment '())

(define the-global-environment (setup-environment))

(define (setup-environment) (let ((initial-env (extend-environment (primitive-procedure-names) (primitive-procedure-objects) the-empty-environment))) (define-variable! 'true #t initial-env) (define-variable! 'false #f initial-env) initial-env))

Page 18: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

21

Summary

• Cycle between eval and apply is the core of the evaluator• eval calls apply with operator and argument values• apply calls eval with expression and environment

• What is still missing from scheme ?• Some special forms• data types other than numbers and booleans

Page 19: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

22

SICP’s version of eval

(define (eval exp env) (cond ((self-evaluating? exp) exp) ((variable? exp) (lookup-variable-value exp env)) ((quoted? exp) (text-of-quotation exp)) ((assignment? exp) (eval-assignment exp env)) ((definition? exp) (eval-definition exp env)) ((if? exp) (eval-if exp env)) ((lambda? exp) (make-procedure (lambda-parameters exp) (lambda-body exp) env)) ((begin? exp) (eval-sequence (begin-actions exp) env)) ((cond? exp) (eval (cond->if exp) env)) ((application? exp) (apply (eval (operator exp) env) (list-of-values (operands exp) env))) (else (error "Unknown expression type -- EVAL" exp))))

Page 20: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

23

Note some minor differences like

(define (self-evaluating? exp) (cond ((number? exp) true) ((string? exp) true) (else false)))

(define (variable? exp) (symbol? exp))

(define (list-of-values exps env) (if (no-operands? exps) '() (cons (eval (first-operand exps) env) (list-of-values (rest-operands exps) env))))

Page 21: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

24

Note: Syntactic Abstraction

• Semantics• What the language means• Model of computation

• Syntax• Particulars of writing expressions• E.g. how to signal different expressions

• Separation of syntax and semantics: allows one to easily alter syntax

eval/applysyntax

procedures

Page 22: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

25

Basic Syntax

• Routines to detect expressions(define (if? exp) (tagged-list? exp 'if))(define (lambda? exp) (tagged-list? exp 'lambda))(define (application? exp) (pair? exp))

• Routines to get information out of expressions(define (operator app) (car app))(define (operands app) (cdr app))(define (first-operand args) (car args))(define (rest-operands args) (cdr args))

• Routines to build expressions(define (make-if predicate consequent alternative)

(list 'if predicate consequent alternative))

Page 23: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

26

Example – Changing Syntax

• Suppose you wanted a "verbose" application syntax:

(CALL <proc> ARGS <arg1> <arg2> ...)

• Changes – only in the syntax routines!

(define (application? exp) (tagged-list? 'CALL))

(define (operator app) (cadr app))

(define (operands app) (cdddr app))

Page 24: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

27

Implementing "Syntactic Sugar"

• Idea:• Implement a simple fundamental "core" in the evaluator• Easy way to add alternative/convenient syntax?

• "let" as sugared procedure application:

(let ((<name1> <val1>) (<name2> <val2>)) <body>)

((lambda (<name1> <name2>) <body>) <val1> <val2>)

Page 25: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

28

Detect and Transform the Alternative Syntax

(define (eval exp env) (cond ((self-evaluating? exp) exp) ((variable? exp) (lookup-variable-value exp env)) ((quoted? exp) (text-of-quotation exp)) . . . ((cond? exp) (eval (cond->if exp) env)) ((let? exp) (eval (let->combination exp) env)) ((application? exp) (apply (eval (operator exp) env)

(list-of-values (operands exp) env))) (else (error "Unknown expression" exp))))

Page 26: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

29

Implementing cond: Syntax procedures

(define (cond-clauses exp) (cdr exp))

(define (cond-else-clause? clause) (eq? (cond-predicate clause) 'else))

(define (cond-predicate clause) (car clause))

(define (cond-actions clause) (cdr clause))

Page 27: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

30

Cond syntax

(cond ((= x 23) (+ x 1))

(else (- x 1)))

cond

else

23x=

1x+

1x-

Page 28: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

31

Transforming sequence of expression toan expression(define (sequence->exp seq) (cond ((null? seq) seq) ((last-exp? seq) (first-exp seq)) (else (make-begin seq))))

(define (make-begin seq) (cons 'begin seq))

2x*

car y

begin

Page 29: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

32

Implementing cond (Cont.)

(cond ((= x 23) (+ x 1))

(else (- x 1)))

(if (= x 23) (+ x 1) (- x 1))

Page 30: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

33

Implementing cond

(define (cond->if exp) (expand-clauses (cond-clauses exp)))

(define (expand-clauses clauses) (if (null? clauses) 'false ; no else clause (let ((first (car clauses)) (rest (cdr clauses))) (if (cond-else-clause? first) (if (null? rest) (sequence->exp (cond-actions first)) (error "ELSE clause isn't last -- COND->IF" clauses)) (make-if (cond-predicate first) (sequence->exp (cond-actions first)) (expand-clauses rest))))))

Page 31: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

34

Details of cond syntax transformation

(cond ((= x 23) (+ x 1))

(else (- x 1)))

cond

else

23x=

1x+

1x-

Page 32: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

35

Details of cond syntax transformation

(expand-clauses

else

23x=

1x+

1x-

)

Page 33: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

36

Details of cond syntax transformation

first

else

23x=

1x+

1x-

rest

Page 34: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

37

Details of cond syntax transformation

23x=

1x+

else

1x-

(make-if

(expand-clauses ))

Page 35: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

38

Details of cond syntax transformation

23x=

1x+

1x-

(make-if

)

Page 36: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

39

Details of cond syntax transformation

23x=

1x+

1x-

if

Page 37: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

40

Named Procedures – Syntax vs. Semantics (define (foo <parm>) <body>)

• Semantic implementation – just another define:(define (eval-definition exp env)

(define-variable! (definition-variable exp)

(eval (definition-value exp) env)

env))

(define (definition-variable exp)

(if (symbol? (cadr exp))

(cadr exp)

(caadr exp)))

(define (definition-value exp)

(if (symbol? (cadr exp))

(caddr exp)

(make-lambda (cdadr exp) ;formal params

(cddr exp)))) ;body

Page 38: 1 The metacircular evaluator (Cont.). 2 6. Defining new procedures (define (lambda? e) (tag-check e 'lambda)) (define (eval exp env) (cond ((number? exp)

41

Read-Eval-Print Loop(define (driver-loop)

(prompt-for-input input-prompt)

(let ((input (read)))

(let ((output (eval input the-global-env)))

(announce-output output-prompt)

(user-print output)))

(driver-loop))

(define (prompt-for-input string) (newline) (newline) (display string) (newline))

(define (announce-output string) (newline) (display string) (newline))

(define (user-print object) (if (compound-procedure? object) (display (list 'compound-procedure (procedure-parameters object) (procedure-body object) '<procedure-env>)) (display object)))

(define input-prompt ";;; M-Eval input:")(define output-prompt ";;; M-Eval value:")