eval-let* exp env

Env. model evaluator:
•
Motivation
Saves repeated renaming and substitution: explicit substitution is replaced by variable
bindings using new data structures (frame, environment).
•
Can be utilized to gain further improvements that cannot be achieved using the
substitution model (The analyzer/compiler)
1
Env. model evaluator:
Structure and implementation
Input text
ASP
Data
structures
Core
Utils
Test
Derived
expressions
(a racket lib)
Data structures:
• New data structures: frame, environment
• Additional procedures are added to handle the new ADTs
• A closure keeps the Env in which it was created.
• renaming and substitution are no longer needed.
Env. model evaluator:
Structure and implementation
Input text
ASP
Data
structures
Core
Utils
Test
Derived
expressions
ASP:
No changes here!
(a racket lib)
Core:
• Procedure application (apply procedure) and evaluation of
expressions are done with respect to a certain environment.
Tests:
• Updated accordingly.
Env. model evaluator:
Structure and implementation
Box, unbox:
•
The global environment may change (E.g., by definitions).
•
Values that may change should be boxed (similar to pointers).
Binding: implemented as a Pair
•
+
A correspondence between a variable and its value.
Frame: Implemented as a substitution
•
#<primitive:+>
‘((x foo) (4 <procedure (x) x>))
A substitution from variables to values. Each variable is bound to a single value.
4
Env. model evaluator:
Structure and implementation
Environment: Implemented as a list of boxed frames
•
A finite sequence of frames in which the last frames is the-global-environment.
box-pointer diagram:
t-g-e
E1
E2
…
box
box
E3
frame
…
frame
‘((foo …) (
proc
‘((+ - …) (prim+ prim- …))
))
params
body
5
Env. model evaluator:
Evaluation examples
(1) Evaluating a definition expression:
> (env-eval (derive '(define f (lambda (x) (lambda (y) (+ x y))))) t-g-e)
(define env-eval
(lambda (exp env)
(cond ((atomic? exp) (eval-atomic exp env))
((special-form? exp) (eval-special-form exp env)) ...)))
(define eval-special-form
(lambda (exp env)
(cond ...
((definition? exp)
(if (not (eq? env t-g-e))
(error 'eval "non global definition: ~s" exp)
(eval-definition exp))) ...)))
(define eval-definition
(lambda (exp)
(add-binding! (make-binding (definition-variable exp)
(env-eval (definition-value exp) t-g-e)))
'ok))
7
Env. model evaluator:
Evaluation example (1)
Evaluating a definition expression:
> (env-eval (derive '(define f (lambda (x) (lambda (y) (+ x y))))) t-g-e)
(define eval-special-form
(lambda (exp env)
(cond ...
((lambda? exp) (eval-lambda exp env)) ...)))
(define eval-lambda
(lambda (exp env)
(make-procedure (lambda-parameters exp)
(lambda-body exp)
env)))
(define make-procedure
(lambda (parameters body env)
(attach-tag (list parameters body env) 'procedure)))
(attach-tag (list '(x) '(lambda (y) (+ x y)) t-g-e)) 'procedure)
t-g-e
P: x
B: (lambda (y) (+ x y))
8
Env. model evaluator:
Evaluation example (1)
Evaluating a definition expression:
> (env-eval (derive '(define f (lambda (x) (lambda (y) (+ x y))))) t-g-e)
(define env-eval
(lambda (exp env)
(cond ((atomic? exp) (eval-atomic exp env))
((special-form? exp) (eval-special-form exp env)) ...)))
(define eval-special-form
(lambda (exp env)
(cond ...
((definition? exp)
(if (not (eq? env t-g-e))
(error 'eval "non global definition: ~s" exp)
(eval-definition exp))) ...)))
(define eval-definition
(lambda (exp)
(add-binding! (make-binding (definition-variable exp)
(env-eval (definition-value exp) t-g-e)))
'ok))
Done!
(add-binding!
(make-binding f (list 'procedure
'(x)
'(lambda (y) (+ x y))
t-g-e))
9
Env. model evaluator:
Evaluation example (2)
Evaluating a user procedure:
> (derive-eval
'f
t-g-e)
(define env-eval
(lambda (exp env)
(cond ((atomic? exp) (eval-atomic exp env))
((special-form? exp) (eval-special-form exp env)) ...)))
(define eval-atomic
(lambda (exp env)
(if (or (number? exp) (boolean? exp) (null? exp))
exp
(lookup-variable-value exp env))))
> '(procedure (x) ((lambda (y) (+ x y))) t-g-e)
•
We look up f in the given env.
•
The result is our representation of a procedure.
10
Env. model evaluator:
Evaluation example (3)
Evaluating an application of a user procedure:
> (derive-eval '(define g (f
1)) t-g-e)
(apply-procedure <procedure (x) ((lambda (y) (+ x y))) t-g-e> (1))
Create a new frame where x maps to 1
(make-frame ‘(x) ‘(1))
Extend the environment
(extend-env new-frame t-g-e)
GE
Evaluate the body
x: 1
(eval-sequence body new-env)
11
Env. model evaluator:
Supporting let*
Reminder: What is a let* expression?
• Can be regarded as a nested let expression.
• Similar to let, but defined variable can be used in the following definitions.
Example:
> (define a 10)
> (let* ((a 1)
(c (* a 2)))
(+ a c))
> (let ((a 1))
(let ((c (* a 2)))
=
(+ a c)))
> ((λ (a)
((λ (c) (+ a c))
=
(* a 2))
1)
> 3
> (let ((a 1)
(c (* a 2)))
(+ a c))
> 21
12
Env. model evaluator:
Supporting let*
Evaluation rule for a let* expression:
An expression (let* ((v1 e1) (v2 e2) … (vn en)) b1 b2 … bm),
with respect to environment E0, is defined as follows:
E1
E2
...
En
E0
E1
* make-frame [(v1),(env-eval e1 E0)]
* make-frame [(v2),(env-eval e2 E1)]
En-1* make-frame [(vn),(env-eval en En-1)]
env-eval b1 En) ... (env-eval bm-1 En)
Return (env-eval bm En)
Q: How would the evaluation rule for let look like?
A: e1…en will be evaluated with respect to E0. A new frame mapping (v1…vn) to (e1…en)
will extend E0, creating a new environment, E1.
13
Env. model evaluator:
Supporting let* - as a derived expression
1. Add the required ADT procedures to the ASP
(define (let*? exp)
(tagged-list? exp 'let*))
(define (let*-first-variable exp)
(caar (let*-bindings exp)))
(define let*-bindings cadr)
(define (let*-first-initial-value exp)
(cadar (let*-bindings exp)))
(define let*-body cddr)
(define (let*-variables exp)
(map car (let*-bindings exp)))
(define (make-let*-bindings vars vals)
(map list vars vals))
(define (let*-initial-values exp)
(map cadr (let*-bindings exp)))
(define (make-let* bindings body)
(append (list 'let* bindings) body))
Data
structures
Core
ASP
Derived
expressions
(let* ((v1 e1) (v2 e2) … (vn en)) b1 b2 … bm)
14
Env. model evaluator:
Supporting let* - as a derived expression
2. Modify the procedure derived?
(define (derived? exp)
(or (cond? exp) (function-definition? exp) (let? exp) (let*? exp)))
3. Modify the procedure shallow-derive
(define (shallow-derive exp)
(cond ((cond? exp)
(cond->if exp))
...
((let*? exp) (let*->nested-let exp))
(else "Unhandled " exp)))
Data
structures
Core
ASP
Derived
expressions
(let* ((v1 e1) (v2 e2) … (vn en)) b1 b2 … bm)
15
Env. model evaluator:
Supporting let* - as a derived expression
4. Add a translation procedure let*->nested-let
(define (let*->nested-let exp)
(let ((bindings (let*-bindings exp))
(body
(let*-body exp)))
(if (null? (cdr bindings))
(make-let bindings body))
(make-let
(make-let-bindings
(list (let*-first-variable exp))
(list (let*-first-initial-value exp)))
(list (make-let* (cdr bindings) body))))))
No changes
to the core!
Data
structures
Core
ASP
Derived
expressions
(let* ((v1 e1) (v2 e2) … (vn en)) b1 b2 … bm)
16
Env. model evaluator:
Supporting let* - as a derived expression
4. Add a translation procedure let*->nested-let
(define (let*->nested-let exp)
(let ((bindings (let*-bindings exp))
(body
(let*-body exp)))
(if (null? (cdr bindings))
(make-let bindings body))
(make-let
(derive
(make-let-bindings
(list (let*-first-variable exp))
(list (let*-first-initial-value exp)))
(let*->nested-let
(list (make-let* (cdr bindings) body))))))
Q: The result is a let exp. Shouldn’t it be further derived?
A: Nah.. It will be taken care of by derive which calls itself until the result exp does not change.
Q: What about the let* expression created by make-let*?
A: Nope. derive is recursively called for all sub expressions.
Q: When the if-condition does not hold, we wrap the body parameter in a list. Why?
A: Since the body of a let expression may consist of several expressions.
17
Env. model evaluator:
Supporting let* - as a special form
1. Add the required ADT procedures to the ASP
Data
structures
Core
ASP
Derived
expressions
(let* ((v1 e1) (v2 e2) … (vn en)) b1 b2 … bm)
18
Env. model evaluator:
Supporting let* - as a special form
2. Modify the procedure special-form?
(define (special-form? exp)
(or (quoted? exp) (lambda? exp) (definition? exp)
(if? exp) (begin? exp) (let*? exp)))
3. Modify eval-special-form
(define (eval-special-form exp env)
(cond ((quoted? exp) (text-of-quotation exp))
((lambda? exp) (eval-lambda exp env))
…
((let*? exp) (eval-let* exp env))))
Data
structures
Core
ASP
Derived
expressions
(let* ((v1 e1) (v2 e2) … (vn en)) b1 b2 … bm)
19
Env. model evaluator:
Supporting let* - as a special form
4. Add the procedure eval-let*
(define (eval-let* exp env)
• Extend the environment with a
(let ((vars (let*-variables exp))
new frame per variable.
(vals (let*-initial-values exp))
• When no variables remain,
(body (let*-body exp)))
evaluate the body.
(letrec ((helper
(lambda (vars-lst vals-lst env)
(if (null? vars-lst)
(eval-sequence body env)
(helper (cdr vars-lst)
(cdr vals-lst)
(extend-env
(make-frame
(list (car vars-lst))
(list (env-eval (car vals-lst) env)))
env))))))
(helper vars vals env))))
20
Env. model Compiler: Motivation
Special form?
What is * ?
(define length
(lambda (lst)
(if (null? lst)
0
(* 1 (length (cdr lst))))))
What’s fact?
Each time fact is called, the interpreter:
•
•
Uses the ASP to identify the body as an if exp,
•
Looks-up variables, etc.
Extracts the required components for evaluation,
To avoid repeated analysis, the compiler:
•
•
•
•
Analyses a given expression in static (compilation) time.
Returns a procedure that awaits an environment argument.
Once applied, it evaluates the analyzed expression with respect to the given environment.
No further Analysis is performed!
21
Env. model Compiler: Introduction
Interpreter vs Compiler:
• Using the compiler, we distinguish analysis from evaluation.
• The compiler returns a procedure ready for execution.
• Given an env, the procedure will evaluate the analyzed code with respect to that env.
• No analysis is performed during evaluation.
(define env-eval
(lambda (exp env)
<body>))
(define analyze
(lambda (exp)
(lambda (env)
<analyzed -body>)))
env-eval:
compiler:
[Exp*Env->Scheme-Type]
[Exp->[Env->Scheme-Type]
22
Env. model Compiler: Comparing with env-eval
The analyze procedure:
(define (analyze exp)
(cond ((atomic? exp) (analyze-atomic exp))
((special-form? exp) (analyze-special-form exp))
((application? exp) (analyze-application exp))
(else
(error "Unknown expression type -- EVAL“ exp))))
Handling an if expression:
(define eval-if (lambda (exp env)
(if (true? (env-eval (if-predicate exp) env))
(env-eval (if-consequent exp) env)
(env-eval (if-alternative exp) env))))
(define analyze-if (lambda (exp)
(let ((pred
(analyze (if-predicate exp)))
(consequent (analyze (if-consequent exp)))
(alternative (analyze (if-alternative exp))))
(lambda (env)
(if (true? (pred env))
(consequent env)
(alternative env))))))
Env. model Compiler: Supporting let*
As a derived expression? Already done in the ASP!
As a special form?
1. Add the required ADT procedures to the ASP
2. identify a let* expression as a special form
3. Modify the procedure analyze-special-form:
(define (analyze-special-form exp)
(cond ((quoted? exp) (analyze-quoted exp))
((lambda? exp) (analyze-lambda exp))
…
((let*? exp) (analyze-let* exp))))
24
Env. model Compiler: Supporting let*
4. Add the procedure analyze-let*:
“Translate” eval-let*, to an analyzer procedure:
• Curry the env parameter.
• Inductively analyze all sub expressions.
(define (analyze-let* exp)
(let ((vars (let*-variables exp))
(vals (map analyze (let*-initial-values exp)))
(body (analyze-sequence (let*-body exp))))
(letrec
((helper (lambda (vars-lst vals-lst env)
(if (null? vars-lst)
(body env)
(helper (cdr vars-lst)
(cdr vals-lst)
(extend-env (make-frame (list (car vars-lst))
(list ((car vals-lst) env)))
env))))))
(lambda (env)
(helper vars vals env)))))
25