Date post: | 05-Jan-2016 |
Category: |
Documents |
Upload: | gillian-farmer |
View: | 222 times |
Download: | 3 times |
1
The environment-based operational semantics
Chapter 4.3
2
What’s Wrong with Substitution?
• On every application we have to:– Rename and substitute: heavy operations– Analyze the body (ask what kind of expression it is
etc)• mixed value/expression. Evaluator value
distinction required
3
The Environment Based Operational Semantics
• Replace local variable management Substitution with A hierarchical environment structure.
• The env-eval algorithm evaluates an expression with respect to an environment.
• Advantage: – Directly access local variables (procedures are
pure code, no need for evaluator value distinction.– Later: Body of procedure may be analyzed once.
4
The Environments Model
Name Value
Environment Table
23score
Substitution model: a single global environment
Environments model: many environments.
5
Binding: a pairing of a name and a valueFrame: a table of bindings
Example: x is bound to 15 in frame A y is bound to (1 2) in frame A the value of the variable x in frame A is 15
21
x: 15
A
y:
6
Environment: a sequence of frames• Environment E1 consists of frames A and B
• Environment E2 consists of frame B only(A frame may be shared by multiple environments)
z: 10
B
E1
E2
x: 15
A
21
y:
this arrow is calledthe enclosing
environment pointer
7
Evaluation in the environment model
• All evaluations occur with respect to an environment
• The current environment changes when theinterpreter applies a procedure
• The top environment is called the global environment (GE)
• Only the GE has no enclosing environment
8
The environment data structureframe is a list of bindings, a variable-value mapping: Variable –> Scheme-type.
environment is a finite sequence of frames E=<f1, f2,..., fn>.
environment diagram
9
Operations on environments and frames:
10
Operations on environments and frames:
11
Operations on environments and frames:
12
The closure data structure
• The closure is the value of a lambda expression.<Closure parameters, body, environment>.
• The components of a closure cl are denoted clparameters , clbody , clenvironment .
• The closure carries the environment it was constructed in.
• this enables the evaluator algorithm to have a lexical scoping policy.
13
The closure data structure• A closure carries an environment - the one containing all local
variables defined when it was created.
>(define f(let ((x 3)) (lambda(y) (+ x y)))
>(f 1)
The interpreter need to know that:• x=3 when evaluating B1.
• This local variable binding needs to be saved for future use of the closure corresponding to (lambda(y) (+ x y)).
• Procedure application involves an extension of that environment.
B2
B1
14
Double bubble: how to draw a procedure
(lambda (x) (* x x))
eval
lambda-rule
A compound procthat squares its
argument
#[proc-...]pr
int
Environmentpointer
Code pointer
parameters: xbody: (* x x)
15
The Environment Model Evaluation Algorithm
16
The Environment Model Evaluation Algorithm - continued
17
The Environment Model Evaluation Algorithm - continued
18
The Environment Model Evaluation Algorithm - continued
19
Notes• The recursive algorithm passes an 'env' parameter• env-eval consults or modify the environment structure in the following
steps:(a) Creation of a compound procedure (closure): Evaluation of a 'lambda'
expression (and 'let').(b) Application of a compound procedure (closure) –
the only way to add a frame (also 'let').(c) Evaluation of 'define' expression – adds a binding to the global
environment.(d) Evaluation of a variable.
• De-allocation of frames: garbage collection...• An environment corresponds to a lexical scope
20
Example 4.7.>(define member
(lambda (x list)(cond ((null list) (list))
((eq? x (car list)) list)(else (member x (cdr list)))))
>(define a (list ’a ’b ’c))>(member ’b a)
Drawing environment diagrams is a way to represent the computation of the env-eval algorithm.
21
Example 4.8. Try a "curried" version of member:>(define c_member
(lambda (list)(lambda (el)
(cond ((null list) (list))((eq? el (car list)) list)(else ((c_member (cdr list))
el))))))
>(define a (list ’a ’b ’c))>(define search-a (c_member a))>(search-a 'b)
22
Example 4.5.
23
Example 4.6.
24
Static (Lexical) vs. Dynamic Scoping Policies(Section 4.3.3)
• Policies for interpreting variables (variable scoping) in a program.
• applicative-eval, normal-eval and env-eval algorithms have a Static (lexical) scoping policy. The nesting of lexical blocks determines the variable binding at run-time
• In dynamic scoping, a variable occurrences is bound by the most recent declaration of that variable.
• In dynamic scoping: the access link is defined by the control link and closures do not carry an environment.
• Do not confuse static scoping with static type-inference algorithms! => languages with static scoping policies allow for static type inference
25
dynamic-env-eval
26
Example 4.6.
• Not all evaluation algorithms are equivalent! dynamic-eval != env-eval(compute the same function, have the same domain)
27
Example 4.10.>(define f
(lambda (x) (a x x)))>(define g
(lambda (a x) (f x)))>(define a +)>(g * 3)
env-eval[(g*3),GE] ==> 6dynamic-env-eval[(g*3),GE] ==> 9
28
Example 4.12.>(define init 0)>(define 1+
(lambda(x)(+ x 1)))>(define f
(lambda (f1)(let ((f2 (lambda () (f1 init))))
(let ((f1 1+) (init 1)) (f2) ))))
>(f (lambda (x) (* x x)))
env-eval[(f (lambda (x) (* x x)))] ==> 0dynamic-env-eval[(f (lambda (x) (* x x)))] ==> 2
29
4.4 The env-eval Evaluator Implementation
1. Abstract Syntax Parser (same as "applicative-eval" implementation) 2. Data structures - environment hierarchy, closures.3. Core ("env-eval" algorithm implementation)
; Type: [<Scheme-exp> -> Scheme-type](define derive-eval
(lambda (exp)(env-eval (derive exp) the-global-environment)))
Chapter 4 - Evaluators for Functional Programming
30
evaluator structure
Scheme expression
Value
evaluator
(Global) Environment
31
Files
Racket-Evaluators\env-functional-interpreter-compiler>dir
analyzer-core.rktanalyzer-tests.rktenv-ds.rktinterpreter-core.rktinterpreter-tests.rkt
32
4.4.2 Data Structures Package4.4.2.1 Procedure ADTs and their implementation
• Primitive procedure: same as in applicative-eval.
33
4.4.2 Data Structures Package4.4.2.1 Procedure ADTs and their implementation
• A Closure (procedure value) - contains an environment in which is was created
34
4.4.2 Data Structures Package4.4.2.1 Procedure ADTs and their implementation
• A Closure (procedure value) - contains an environment in which is was created
• Identify procedures in general
35
4.4.2.2 Environment related ADTs and their implementations:
• The interpreter holds a "DrRacket" variable the-global-environment
* Bindings, Frames, Environments.
36
4.4.2.2 Environment related ADTs and their implementations:
The Binding ADT and its implementation:
Alternative definition:(define make-binding cons)(define binding-variable car)(define binding-value cdr)What is the difference?
var val
binding
37
4.4.2.2 Environment related ADTs and their implementations:The Frame ADT and its implementation:
(define make-frame (lambda (variables values) (make-sub variables values)))
(define make-sub (lambda (variables values) (let ((sub (list variables values))) (if (sub? sub) sub (error …)))))
38
4.4.2.2 Environment implementation• An environment is implemented as a list of boxed (mutable) frames.
environment
frame substitution
frame substitution
frame substitution
* in implementation language
box
variable->value lookup function
Racket box operationsbox(x)unbox(b)set-box!(b, y)
39
4.4.2.2 Global environment construction
40
41
(define lookup-variable-value (lambda (env var) (letrec ((defined-in-env (lambda (var env) (if (empty-env? env) env (let ((b (get-value-of-variable (first-frame env) var))) (if (eq? b '_not-found) (defined-in-env var (enclosing-env env)) b)))))) (let ((b (defined-in-env var env))) (if (empty? b) (error 'lookup "variable not found: ~s\n env = ~s" var env) b)))))
42
(define get-value-of-variable (lambda (sub var) (letrec ((lookup (lambda (vars vals) (cond ((or (empty-sub? sub) (not (member var vars))) '_not-found) ((eq? var (car vars)) (car vals)) (else (lookup (cdr vars) (cdr vals))))))) (lookup (get-variables sub) (get-values sub)))))
43
; Global environment mutator: ADT type is [Binding -> Unit]; Type: [PAIR(Symbol,T) -> Unit]; Note: Mutation is enabled only for the global environment(define add-binding! (lambda (binding) (let ((frame (first-frame the-global-environment))) (set-box! (first-boxed-frame the-global-environment) (extend-frame binding frame)))))
44
4.4.1.1 Main evaluator loop:
45
46
47
4.4.1.2 Evaluation of atomic expressions
48
49
50
4.4.1.4 Evaluation of applications
; Type: [Evaluator-procedure*LIST -> Scheme-type](define apply-procedure (lambda (procedure arguments) (cond ((primitive-procedure? procedure) (apply-primitive-procedure procedure arguments)) ((compound-procedure? procedure) (let* ((parameters (procedure-parameters procedure)) (body (procedure-body procedure)) (env (procedure-environment procedure)) (new-env (extend-env (make-frame parameters arguments) env))) (eval-sequence body new-env))) (else (error 'apply "unknown procedure type: ~s" procedure)))))
52
Primitive procedure application
53
Testing(define (app-lambda-tests) (test (derive-eval '((lambda (x) x) 12)) => 12) (test
(derive-eval '((lambda (x y z) (+ x y z)) 12 13 14))
=> 39)...
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Invoking tests;;;;;;;;;;;;;;;;;;;;;;;;;;;;;(app-lambda-tests)
54
The Analyzer
So far, no distinction between syntax analysis and evaluation
For example: the kind of an expression (special form, application etc) can be decided statically.
55
Files
Racket-Evaluators\env-functional-interpreter-compiler>dir
analyzer-core.rktanalyzer-tests.rktenv-ds.rktinterpreter-core.rktinterpreter-tests.rkt
56
4.5.1 The Analyzer
• Compile time (static time): Things performed first, once if possible. – static syntax analysis
• Run time (dynamic time): Things performed later, as needed – data-structure (environments and closures) related
• Compile time is less expensive than run time.
• Analyzing a procedure body once, independently from its application, means compiling its code into something more efficient/optimal, which is ready for evaluation.
Chapter 4 - Evaluators for Functional Programming
57
analyzer structure
Scheme expression
Value
(Global) Environment
syntax-analysis(compilation)
run-time evaluation
Program in target
language
code in the implementation language.
58
4.5 An Environment-based FP Meta-Circular CompilerThe analyzer
• avoid repetition of syntax-analysis in every procedure application.
• Idea: separate static syntax analysis (syntax parsing)from run-time evaluation (closure/environment data-structure manipulation).
• means: curried function style.
59
An Environment-based FP Meta-Circular Compiler
The analyzer• Use curryingInterpreter: Compiler:(lambda (exp env) (lambda (exp)
syntax analysis+ syntax analysis run-time evaluation (performed once)
returns(lambda(env)
run-time evaluation[Expression*Env->T] [Expression->[Env->T]]
• Compiler output is code in the implementation language.
60
Environment-based compiler(define derive-analyze-eval
(lambda(exp)((analyze (derive exp)) the-global-environment))
(define analyze(lambda (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)))))
61
Environment-based compiler• Interpreter: (define eval-atomic
(lambda (exp env)(if (or (number? exp) (boolean? exp) (null? exp))
exp
(lookup-variable-value exp env))))
• Compiler: (define analyze-atomic
(lambda (exp)(if (or (number? exp) (boolean? exp) (null? exp))
(lambda (env) exp)(lambda (env) (lookup-variable-value exp env)))))
62
Environment-based compiler• Interpreter:(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))))
• Compiler:(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))))))
63
Environment-based compiler• Interpreter(define eval-lambda
(lambda (exp env)(make-procedure (lambda-parameters exp)
(lambda-body exp) env)))
• Compiler - body is analyzed once!(define analyze-lambda
(lambda (exp)(let ((parameters (lambda-parameters exp)) (body (analyze-sequence (lambda-body exp)))) (lambda (env)
(make-procedure parameters body env))))
64
Environment-based compiler(define analyze-sequence
(lambda (exps)(let ((procs (map analyze exps)) (last-in-list (lambda (lst) (car (reverse
lst))))) (if (null? procs)
(error "Empty sequence -- ANALYZE"))(lambda (env) (let ((vals (map (lambda (proc)(proc env))
procs))) (last-in-list vals)))))
• relies on the order of map in the underlining (implementation) Scheme.
65
Environment-based compiler• Interpreter(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))
66
Environment-based compiler• Compiler:(define (analyze-definition
(lambda (exp)(let ((var (definition-variable exp)) (val (analyze (definition-value exp)))) (lambda (env)
(if (not (eq? env the-global-environment)) (error "Non global definition" exp) (begin (add-binding!
(make-binding var (val the-global-
environment))) ’ok))))))
67
• Interpreter:(define env-eval
(lambda (exp env)(cond ... ((application? exp)(apply-procedure (env-eval (operator exp) env) (list-of-values (operands exp) env)))...
Compiler: (define analyze
(lambda (exp)(cond ... ((application? exp) (analyze-application exp))...
(define analyze-application(lambda (exp)
(let ((application-operator (analyze (operator exp))) (application-operands (map analyze (operands exp)))) (lambda (env)(apply-procedure(application-operator env)(map (lambda (operand) (operand env)) application-operands))))))
68
• Interpreter:(define apply-procedure (lambda (procedure args)
(cond ((primitive-procedure? procedure) (apply-primitive-procedure procedure args))
((compound-procedure? procedure) (let
((proc-params (procedure-parameters procedure))
(proc-body (procedure-body procedure))(proc-env (procedure-environment procedure)))
(eval-sequence proc-body
(extend-env (make-frame proc-params args)
proc-env))(else (error ... )))))
69
• Compiler - evaluation of analyzed operator on extended environment(define apply-procedure
(lambda (procedure args) (cond ((primitive-procedure? procedure)
(apply-primitive-procedure procedure args)) ((compound-procedure? procedure)
(let ((proc-params (procedure-parameters procedure)))
(proc-abody (procedure-body procedure))
(proc-env (procedure-environment procedure)))
(proc-abody (extend-env
(make-frame proc-params args) proc-env))
(else (error ... )))))
70
No repeated analysis - Tracing example> (require racket/trace) > (trace analyze)> (derive-analyze-eval ’(define (factorial n) (if (= n 1) 1 (*
(factorial (- n 1)) n)))| (analyze (define factorial (lambda(n) (if (= n 1) 1 (* (factorial (- n
1)) n))))| |(analyze (lambda (n) (if (= n 1) 1 (* (factorial (- n 1)) n))))| | (analyze (if (= n 1) 1 (* (factorial (- n 1)) n)))| | |(analyze (= n 1))| | | (analyze =)| | | #<procedure>| | | (analyze n)| | | #<procedure>| | | (analyze 1)| | | #<procedure>| | |#<procedure> // returned from analyze '(= n 1)
71
| | |(analyze 1)| | |#<procedure>| | |(analyze (* (factorial (- n 1)) n))| | | (analyze *)| | | #<procedure>| | | (analyze (factorial (- n 1)))| | | |(analyze factorial)| | | |#<procedure>| | | |(analyze (- n 1))| | | | (analyze -)| | | | #<procedure>| | | | (analyze n)| | | | #<procedure>| | | | (analyze 1)| | | | #<procedure>| | | |#<procedure> // returned from analyze '(- n 1) | | | #<procedure> // returned from analyze '(factorial (- n 1))| | | (analyze n)
72
No repeated analysis - example| | | #<procedure>| | |#<procedure> // returned from analyze '( * (factorial...| | #<procedure> // returned from analyze '(if ...| |#<procedure> // returned from analyze '(lambda ...| #<procedure> // returned from analyze '(define ...)|ok // returned from application on the-global-environment
> (derive-analyze-eval ’(factorial 4))|( (analyze (factorial 4)) the-global-environment)| (analyze (factorial 4))| |(analyze factorial)| |#<procedure> // returned from analyze 'factorial| |(analyze 4)| |#<procedure> // returned from analyze 4| #<procedure> // returned from analyze '(factorial 4)|24 // returned from application on the-global-environment
// no recursive analysis when recursive analyzed procedure is applied!!
73
Chapter 4 Summary• Interpreter algorithms that have a static scoping policy:
applicative-eval, env-eval and normal-eval are functionally equivalent (on the domain conjunction).
• An interpreter algorithm that has a dynamic scoping policy.dynamic-env-eval
• Implementations for applicative-eval, env-eval :use ASP (incl. handling expression derivation), Data structures (environments, procedure and other values), have test modules.
• Analyzer optimization for the environment based interpreter.