Date post: | 01-Jan-2016 |
Category: |
Documents |
Upload: | evan-salazar |
View: | 18 times |
Download: | 0 times |
1
The environment model evaluator and compilerThe env model evaluator Motivation
• Saves repeated renaming and substitution: Using new data
structures (frame, environment), explicit substitution is replaced
by variable bindings.
• Can be utilized to gain further improvements that cannot be
achieved using the substitution model (coming up next..)
2
The environment model evaluator and compilerThe env model evaluator Structure & implementation
Data structures
Abstract syntax parser
Core
Derived expressions
Special forms
No changes here!
• New data structures:• A closure• A binding• A frame• An environment
• Additional procedures to handle with these ADTs
• Procedure application and evaluation of expressions is now done with respect to a certain environment.
• No need for renaming & substitution procedures.
3
The environment model evaluator and compilerThe env model evaluator Structure & implementation
A closure: The data structure representing a procedure value includes, in
addition to its params and body, also the env in which the procedure has been
declared. This env is to be extended when applying the procedure.
Data structures package:
A binding: A pair consisting of a variable and its value.
#<primitive:+>
+
P:B:
env
4
The environment model evaluator and compilerThe env model evaluator Structure & implementation
A frame:
• A variable-value mapping. Every variable in a frame is bound to one value only.
• Implemented as a pair of lists: a list of variables and a list of values.
Data structures package:
#<primitive:+> #<procedure>
+ x
3
f
5
The environment model evaluator and compilerThe env model evaluator Structure & implementation
An environment:
• A finite sequence of frames in which the last frame is the global environment.
• Implemented as a list of frames.
Data structures package:E2
+ Implementation
…
…
… …
+
*
cons
x
y
3
4
* Implementation
cons Implementation
E3
E1
6
The environment model evaluator and compilerThe env model evaluator Structure & implementation
“Our” global environment is referenced by a variable in Dr.Scheme!
• A finite sequence of frames in which the last frame is the global environment.
• Implemented as a list of frames.
+ Implementation
… …
+
*
cons * Implementation
cons Implementation
t-g-e
“ Dr.Scheme’s global environment “
7
(define env-eval (lambda (exp env)
(cond ((atomic? exp) (eval-atomic exp env)) ((special-form? exp) (eval-special-form exp env)) ((application? exp)
(apply-procedure (env-eval (operator exp) env) (list-of-values (operands exp) env)))
(else (error "Unknown expression type -- EVAL" exp)))))
env-eval (functional-env-core.scm)
The environment model evaluator and compilerThe env model evaluator Structure & implementation
The environment model evaluator and compiler
8
The env model evaluator Example 1
> (env-eval '(define f (lambda (x) (lambda (y) (+ x y)))) t-g-e)
((special-form? exp) (eval-special-form exp env))
(define eval-special-form (lambda (exp env)(cond … ((definition? exp) (if (not (eq? env the-global-environment))
(error "Non global definition" exp) (eval-definition exp))) …
(define eval-definition (lambda (exp)
(add-binding! (make-binding (definition-variable exp) (env-eval (definition-value exp) the-global-environment)))
'ok))
9
The environment model evaluator and compiler
(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)))
> (env-eval '(define f (lambda (x) (lambda (y) (+ x y)))) t-g-e)
((special-form? exp) (eval-special-form exp env))
The env model evaluator Example 1
10
The environment model evaluator and compiler
(define make-procedure (lambda (parameters body env) (attach-tag (list parameters body env) 'procedure))) P:
B:
env
> (env-eval '(define f (lambda (x) (lambda (y) (+ x y)))) t-g-e)
Q: Why use list and not just return '(procedure (x) (lambda (y) (+ x y)) t-g-e)?
A: If we did, t-g-e would have been quoted, thus producing a symbol instead of
the data structure that represents the global environment used by our evaluator.
The env model evaluator Example 1
11
The environment model evaluator and compiler
> (env-eval '(define f (lambda (x) (lambda (y) (+ x y)))) t-g-e)
Back to the original expression: Bind f with the created closure in our GE.
(add-binding! (make-binding f (list 'procedure '(x) '(lambda (y) (+ x y)) t-g-e)))
(define eval-definition (lambda (exp)
(add-binding! (make-binding (definition-variable exp) (env-eval (definition-value exp) the-global-environment)))
'ok))
The env model evaluator Example 1
The environment model evaluator and compiler
> (env-eval '(define f (lambda (x) (lambda (y) (+ x y)))) t-g-e)
> t-g-e
#0=( ( (f + * cons null?) (procedure (x) ((lambda (y) (+ x y))) #0#) (primtive #<primitive:+>) (primitive #<primitive:*>) (primitive #<primitive:cons>) (primitive #<primitive:null?>) ) )
…
…
+
*
cons cons
Imp.
f
'procedure
x
'lambda
'y 'y'x'+
t-g-e
+Imp.*
Imp.
12
• The resulting structure is circular.
The env model evaluator Example 1
13
The environment model evaluator and compiler
> (env-eval ‘f t-g-e)
(define eval-atomic (lambda (exp env) (if (or (number? exp) (boolean? exp) (null? exp)) exp (lookup-variable-value exp env))))
• We look up f in the given env.
• The result is our representation of a
procedure: a tagged list storing the
body, the params and the env where
the procedure was defined.
• The resulting structure is circular.
#0=(procedure (x) ((lambda (y) (+ x y))) (((f + * cons null?) #0# (primitive #<primitive:+>) (primitive #<primitive:*>) (primitive #<primitive:cons>) (primitive #<primitive:null?>))))
The env model evaluator Example 2
The environment model evaluator and compiler
> (env-eval '(define g (f 1) ) t-g-e)
((application? exp) (apply-procedure (env-eval (operator exp) env) (list-of-values (operands exp) env)))
(apply-procedure (procedure (x) ((lambda (y) (+ x y))) t-g-e) (1))
1. Extend the env in which the procedure was defined with a new frame.
2. Within this frame, bind x to 1.
(procedure #0=(y)#1=((+ x y))( (#2=(x) 1) . #3=(((f + * cons null?)
(procedure #2# ((lambda #0# . #1#)) #3#)
(primitive #<primitive:+>)(primitive #<primitive:*>)(primitive #<primitive:cons>)(pimitive #<primitive:null?>)))
))
GE (#3)
x: 1
(#2)
14
The env model evaluator Example 3
The environment model evaluator and compiler
15
'procedure
…
f
+
*
g
'y'x'+
x 1
E1
'procedure
‘x
'lambda
'y 'y'x'+
t-g-e
…cons
Imp.
+Imp.*
Imp.
‘y
The env model evaluator Example 3
The environment model evaluator and compiler
16
What is a let* expression?• Similar to a let, only that every defined variable can be used in the following definitions.
• Can be regarded as a nested let expression.
• The number of variables corresponds to the number of nested let expressions.
>(let* ((a 1) (c (* a 2)))(+ a c))
3
>(let ((a 1) (c (* a 2))) (+ a c))
21
>(define a 10)
>(let ((a 1)) (let ((c (* a 2))) (+ a c)))
>((λ (a) ((λ (c) (+ a c)) (* a 2)) 1)
Supporting a let* expression
The env model evaluator Adding a let* exp
The environment model evaluator and compiler
17
Evaluation rule for let* expressions: The evaluation rule for an expression (let* ((v1 e1) (v2 e2) … (vn en)) b1 b2 … bm), with respect to
an environment E0, is defined as follows:
E1 E0 * make-frame [(v1),(env-eval e1 E0)]E2 E1 * make-frame [(v2),(env-eval e2 E1)]...En 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: There will be only one frame extending E0 and creating a new environment E1.
All of the expressions e1…en will be evaluated with respect to E0.
The env model evaluator Adding a let* expression
The environment model evaluator and compiler
18
Supporting a let* expression: As a special form
1. Add the required ADT procedures to the ASP
ASPASP
Derived expressions
Derived expressions
Core
Special forms
Data Structures(+GE)
(define (let*? exp) (tagged-list? exp 'let*))
(define let*-bindings cadr)
(define let*-body cddr)
(define (let*-variables exp) (map car (let*-bindings exp)))
(define (let*-initial-values exp) (map cadr (let*-bindings exp)))
(define (let*-first-variable exp) (caar (let*-bindings exp)))
(define (let*-first-initial-value exp) (cadar (let*-bindings exp)))
(define (make-let*-bindings vars vals) (map list vars vals))
(define (make-let* bindings body) (append (list 'let* bindings) body))
(let* ((v1 e1) (v2 e2) … (vn en)) b1 b2 … bm)
The environment model evaluator and compilerThe env model evaluator Adding let* as a special form
19
2. Add the required changes to identify a let* expression as a special formASP
Derived expressions
Core
Special forms
Data Structures(+GE)
(define (special-form? exp) (or (quoted? exp) (lambda? exp) (definition? exp) (if? exp) (begin? exp) (let*? exp)))
(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))))
(let* ((v1 e1) (v2 e2) … (vn en)) b1 b2 … bm)
How would eval-let* work?
The environment model evaluator and compilerSupporting a let* expression: As a special formThe environment model evaluator and compilerThe env model evaluator Adding let* as a special form
20
3. Add the required changes to evaluate a let* expression
(let* ((v1 e1) (v2 e2) … (vn en)) b1 b2 … bm)
(define (eval-let* exp env) (let ((body (let*-body exp))) (if (null? (let*-bindings exp)) (eval-sequence body env) (let ( (first-var (let*-first-variable exp)) (first-val (let*-first-initial-value exp)) (rest-bindings (let*-rest-bindings exp)) )
(eval-let* (make-let* rest-bindings body) (extend-env ( make-frame (list first-var)
(list (env-eval first-val env)) ) env ))))))
Option A:
Create a new, smaller let* expression and recursively evaluate it with respect to an extended env.
The environment model evaluator and compilerSupporting a let* expression: As a special formThe environment model evaluator and compilerThe env model evaluator Adding let* as a special form
21
(define (eval-let* exp env) (let ( (vars (let*-variables exp)) (vals (let*-initial-values exp)) (body (let*-body exp)) ) (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))))
Option B:
Keep extending the given env with new frames. When vars-lst becomes empty, No more extensions are needed. It only remain to evaluate the body.
(let* ((v1 e1) (v2 e2) … (vn en)) b1 b2 … bm)
3. Add the required changes to evaluate a let* expression
Q: How is option B different from option A?A: In option A we create code in run-time (when calling make-let*).
The environment model evaluator and compilerSupporting a let* expression: As a special formThe environment model evaluator and compilerThe env model evaluator Adding let* as a special form
22
1. Add the required ADT procedures to the ASP: Same as earlier!
ASPASP
Derived expressions
Derived expressions
Core
Special forms
Data Structures(+GE)
2. Add the required changes to identify a let* expression as a derived
expression(define (derived? exp) (or (cond? exp) (function-definition? exp) (let? exp) (let*? exp)))
(define (shallow-derive exp) (cond ((cond? exp) (cond->if exp)) … ((let*? exp) (let*->nested-let exp)) (else "Unhandled derivision" exp)))
3. Support a let* expression in the shallow-derive procedure
How will let*->nested-let work?
The environment model evaluator and compilerSupporting a let* expression: As a special formThe environment model evaluator and compilerThe env model evaluator Adding let* as a derived exp
23
4. Provide with a procedure to derive a let* expression(define (let*->nested-let exp) (let ( (bindings (let*-bindings exp)) (body (let*-body exp)) ) (if (null? (cdr bindings)) (derive (make-let bindings body)) (derive (make-let (make-let-bindings (list (let*-first-variable exp))
(list (let*-first-initial-value exp))) (list (let*->nested-let (make-let* (cdr bindings) body))))))))
Q1: Why do we use derive in the body of let*->nested-let?A1: We derive let* into nested let expressions, but let is a derived expression itself. We must derive it so the evaluator can handle it.
Q2: In the alternative clause, we enclose the body parameter for make-let in a list. Why?A2: Since the body may include a sequence of expressions, make-let expects a list. let*->nested-let returns a single expression, so we must enclose it within a list to be given as an argument to make-let.
The environment model evaluator and compilerSupporting a let* expression: As a special formThe environment model evaluator and compilerThe env model evaluator Adding let* as a derived exp
24
• Env-eval combines expression analysis and evaluation in the same process.
• This leads to inefficiency due to repeated analysis (repeated calls for ASP procedures).
• We avoid this by separating analysis from evaluation.
• This could not be achieved in the substitution model, where every application involves
substitution and analysis.
The environment model evaluator and compilerSupporting a let* expression: As a special formThe environment model evaluator and compilerThe env model compiler What is it good for?
We analyze our code, producing a procedure that is ready for execution, given an
environment argument. The procedure returns the evaluation of the analyzed code with
respect to the given environment. No analysis is performed during the evaluation.
(define env-eval (lambda (exp env) <body>))
(define analyze (lambda (exp) (lambda (env) <analyzed -body>)))
25
The environment model evaluator and compilerSupporting a let* expression: As a special formThe environment model evaluator and compiler
(define fact (lambda (n) (if (= n 0) 1 (* n (fact (- n 1))))))
Compiler:
• To avoids repeated analysis, Takes an exp, performs analysis in static time and returns
a procedure that awaits an environment argument.
• Once the procedure is applied, it evaluates the analyzed exp with respect to the given
environment. No further analysis is performed.
Interpreter:
Each time fact is called, the interpreter repeatedly uses ASP
procedures to identify the body as an if expression and to get the
required components for evaluation.
env-eval:Exp*Env->Scheme-Type
compiler:Exp->[Env->Scheme-Type]
The env model compiler What is it good for?
26
The environment model evaluator and compilerSupporting a let* expression: As a special formThe environment model evaluator and compiler
(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))))
The env model compiler Example
(define (eval-if exp env) (if (true? (env-eval (if-predicate exp) env)) (env-eval (if-consequent exp) env) (env-eval (if-alternative exp) env)))
Evaluator code for if-expression
(define (analyze-if 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)))))
Compiler code for if-expression
The analysis of an if expression is performed only once. It saves us the calls for ASP procedure for the evaluation during run-time. The returned procedure performsevaluation only.
27
(define (analyze-special-form exp) (cond ((quoted? exp) (analyze-quoted exp)) ((lambda? exp) (analyze-lambda exp)) … ((let*? exp) (analyze-let* exp))))
How will analyze-let* work?
The environment model evaluator and compilerSupporting a let* expression: As a special formThe environment model evaluator and compilerThe env model compiler Adding a let* expression
What should be done to add let* as a derived expression?Same thing we did with the evaluator!
How would we support a let* expression as a special form?1. Add the required ADT procedures to the ASP
2. identify a let* expression as a special form
3. Support a let* expression in the analyze-special-form procedure:
28
The environment model evaluator and compilerSupporting a let* expression: As a special formThe environment model evaluator and compilerThe env model compiler Adding a let* expression
4. Provide with a procedure to analyze a let* expression:• Take an evaluator procedure that evaluates a let* expression.• Curry the env parameter.• inductively apply analyze to all sub expressions.
(define (eval-let* exp env) (let ((body (let*-body exp))) (if (null? (let*-bindings exp)) (eval-sequence body env) (let ( (first-var (let*-first-variable exp)) (first-val (let*-first-initial-value exp)) (rest-bindings (let*-rest-bindings exp)) )
(eval-let* (make-let* rest-bindings body) (extend-env ( make-frame (list first-var)
(list (env-eval first-val env)) ) env ))))))
Option A: What’s wrong with it?
It produces code on run-time, which we cannot analyze. Analysis is
performed ONLY on static time, before evaluation!
29
The environment model evaluator and compilerSupporting a let* expression: As a special formThe environment model evaluator and compilerThe env model compiler Adding a let* expression
The second version for eval-let* (option B) translated into analyze-let*:(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) ;letrc body – carrying (helper vars vals env)))))
Note: If we were to support let* as a derived expression, we would have used derive-analyze-eval