Title: The metacircular evaluator (Cont.)
1The metacircular evaluator (Cont.)
26. 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))
3 (eval '(define twice (lambda (x) ( x x))) GE)
4Implementation 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)
5Naming the procedure
- (eval '(define twice (lambda (x) ( x x)))
GE)
names values z 9 true t twice
symbolprocedure
66. 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))
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))
8How the Environment Works
- Abstractly in our environment diagrams
- Concretely our implementation (as in SICP)
9Extending the Environment
Abstractly
- (extend-environment '(x y) (list 4 5) E2)
Concretely
10(define (extend-environment vars vals base-env)
(if ( (length vars) (length vals)) (cons
(make-frame vars vals) base-env) (if (lt
(length vars) (length vals)) (error
"Too many arguments supplied" vars vals)
(error "Too few arguments supplied" vars
vals))))
11(eval '(twice 4) GE)
12Implementation 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)
13Implementation 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
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
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 (enclosing-environment env) (cdr env))
(define (frame-variables frame) (car
frame)) (define (frame-values frame) (cdr frame))
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))
17The Initial (Global) Environment
(define (setup-environment) (let ((initial-env
(extend-environment (primitive-procedure-n
ames)
(primitive-procedure-objects)
the-empty-environment)))
(define-variable! 'true t initial-env)
(define-variable! 'false f initial-env)
initial-env))
(define the-empty-environment '())
(define the-global-environment (setup-environment)
)
18Is eval an iterative or recursive algorithm?
- It depends on the scheme program being evaluated
- An iterative algorithm in scheme
- (eval '(define odd (lambda (n) (odd
(- n 2)))) GE) - A recursive algorithm in scheme
- (eval '(define sum (lambda (n) ( n
(sum (- n 1))))) GE) - Base case and if check omitted from both
algorithmsto simplify the example
19- (eval '(define odd (lambda (n) (odd (- n
2)))) GE) - gt undefined
- (eval '(odd 4) GE)
- call apply, which creates E1 n 4, then eval
body of odd - (eval '(odd (- n 2)) E1)
- (apply (eval 'odd E1) (list (eval '(- n 2)
E1))) - skip some steps in which (- n 2) gt 2
- (apply (list procedure '(n) '(odd (- n
2)) GE) '(2)) - apply creates E2 n 2, then eval body of odd
- (eval '(odd (- n 2)) E2))
- No pending operations on the recursive call to
eval
20- (eval '(define sum (lambda (n)( n (sum (- n
1))))) GE) - (eval '(sum 4) GE)
- call apply, which creates E1 n 4, then eval
body of sum - (eval '( n (sum (- n 1))) E1)
- (apply '(primitive add) (list (eval 'n
E1) (eval '(sum (- n 1)) E1))) - skip some steps in which (- n 1) gt 3
- (apply '(primitive add) (list 4 (apply (eval
'sum E1) '(3)))) - apply creates E2 n 3, then eval body of
sum - (apply '(primitive add)(list 4 (eval '( n
(sum (- n 1))) E2)) - There are pending operations on the recursive
call to eval
21Summary
- 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
22SICPs 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-gtif exp) env)) ((application?
exp) (apply (eval (operator exp) env)
(list-of-values (operands exp)
env))) (else (error "Unknown
expression type -- EVAL" exp))))
23Note 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))))
24Note 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
25Basic 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))
26Example Changing Syntax
- Suppose you wanted a "verbose" application
syntax - (CALL ltprocgt ARGS ltarg1gt ltarg2gt ...)
- Changes only in the syntax routines!
- (define (application? exp) (tagged-list? 'CALL))
- (define (operator app) (cadr app))
- (define (operands app) (cdddr app))
27Implementing "Syntactic Sugar"
- Idea
- Implement a simple fundamental "core" in the
evaluator - Easy way to add alternative/convenient syntax?
- "let" as sugared procedure application
- (let ((ltname1gt ltval1gt)
- (ltname2gt ltval2gt))
- ltbodygt)
- ((lambda (ltname1gt ltname2gt) ltbodygt)
- ltval1gt ltval2gt)
28Detect 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-gtif exp) env))
- ((let? exp)
- (eval (let-gtcombination exp) env))
- ((application? exp)
- (apply (eval (operator exp) env)
- (list-of-values
- (operands exp)
env))) - (else (error "Unknown expression" exp))))
29Implementing 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))
30Cond syntax
(cond (( x 23) ( x 1)) (else (- x 1)))
cond
else
-
x
x
x
31Transforming sequence of expression toan
expression
(define (sequence-gtexp seq) (cond ((null? seq)
seq) ((last-exp? seq) (first-exp seq))
(else (make-begin seq)))) (define
(make-begin seq) (cons 'begin seq))
32Implementing cond (Cont.)
(cond (( x 23) ( x 1)) (else (- x 1)))
(if ( x 23) ( x 1) (- x 1))
33Implementing cond
(define (cond-gtif 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-gtexp (cond-actions first))
(error "ELSE clause isn't last -- COND-gtIF"
clauses))
(make-if (cond-predicate first)
(sequence-gtexp (cond-actions first))
(expand-clauses rest))))))
34Details of cond syntax transformation
(cond (( x 23) ( x 1)) (else (- x 1)))
cond
else
-
x
x
x
35Details of cond syntax transformation
(expand-clauses
else
-
x
x
)
x
36Details of cond syntax transformation
rest
first
else
-
x
x
x
37Details of cond syntax transformation
(make-if
))
(expand-clauses
else
-
x
38Details of cond syntax transformation
(make-if
)
39Details of cond syntax transformation
if
40Named Procedures Syntax vs. Semantics
- (define (foo ltparmgt) ltbodygt)
- 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
41Read-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)
'ltprocedure-envgt)) (display object)))
(define input-prompt " M-Eval input") (define
output-prompt " M-Eval value")