Download presentation
Presentation is loading. Please wait.
Published byGillian Farmer Modified over 9 years ago
1
The environment-based operational semantics Chapter 4.3 1
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 2
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. 3
4
4 The Environments Model Name Value Environment Table 23 score Substitution model: a single global environment Environments model: many environments.
5
5 Binding: a pairing of a name and a value Frame: 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 2 1 x: 15 A y:
6
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 2 1 y: this arrow is called the enclosing environment pointer
7
7 Evaluation in the environment model All evaluations occur with respect to an environment The current environment changes when the interpreter applies a procedure The top environment is called the global environment (GE) Only the GE has no enclosing environment
8
The environment data structure frame is a list of bindings, a variable-value mapping: Variable –> Scheme-type. environment is a finite sequence of frames E=. 8 environment diagram
9
Operations on environments and frames: 9
10
10
11
Operations on environments and frames: 11
12
The closure data structure The closure is the value of a lambda expression.. The components of a closure cl are denoted cl parameters, cl body, cl environment. The closure carries the environment it was constructed in. this enables the evaluator algorithm to have a lexical scoping policy. 12
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 B 1. 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. 13 B2B2 B1B1
14
14 Double bubble: how to draw a procedure (lambda (x) (* x x)) eval lambda-rule A compound proc that squares its argument #[proc-...] print Environment pointer Code pointer parameters: x body: (* x x)
15
The Environment Model Evaluation Algorithm 15
16
The Environment Model Evaluation Algorithm - continued 16
17
17 The Environment Model Evaluation Algorithm - continued
18
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 19
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) 20 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) 21
22
Example 4.5. 22
23
Example 4.6. 23
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 24
25
dynamic-env-eval 25
26
Example 4.6. 26 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] ==> 6 dynamic-env-eval[(g*3),GE] ==> 9 27
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)))] ==> 0 dynamic-env-eval[(f (lambda (x) (* x x)))] ==> 2 28
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-type] (define derive-eval (lambda (exp) (env-eval (derive exp) the-global-environment))) 29
30
evaluator structure Chapter 4 - Evaluators for Functional Programming 30 Scheme expression Value evaluator (Global) Environment
31
Files Racket-Evaluators\env-functional-interpreter-compiler>dir analyzer-core.rkt analyzer-tests.rkt env-ds.rkt interpreter-core.rkt interpreter-tests.rkt 31
32
4.4.2 Data Structures Package 4.4.2.1 Procedure ADTs and their implementation Primitive procedure: same as in applicative-eval. 32
33
4.4.2 Data Structures Package 4.4.2.1 Procedure ADTs and their implementation A Closure (procedure value) - contains an environment in which is was created 33
34
4.4.2 Data Structures Package 4.4.2.1 Procedure ADTs and their implementation A Closure (procedure value) - contains an environment in which is was created Identify procedures in general 34
35
4.4.2.2 Environment related ADTs and their implementations: 35 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 : 36 Alternative definition: (define make-binding cons) (define binding-variable car) (define binding-value cdr) What is the difference? varval binding
37
4.4.2.2 Environment related ADTs and their implementations: The Frame ADT and its implementation: 37 (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. 38 environment frame substitution * in implementation language box variable->value lookup function Racket box operations box(x) unbox(b) set-box!(b, y)
39
39 4.4.2.2 Global environment construction
40
40
41
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
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
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: 44
45
45
46
46
47
47 4.4.1.2 Evaluation of atomic expressions
48
48
49
49
50
50
51
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 52
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) 53
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. 54
55
Files Racket-Evaluators\env-functional-interpreter-compiler>dir analyzer-core.rkt analyzer-tests.rkt env-ds.rkt interpreter-core.rkt interpreter-tests.rkt 55
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. 56
57
analyzer structure Chapter 4 - Evaluators for Functional Programming 57 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 Compiler The 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. 58
59
An Environment-based FP Meta-Circular Compiler The analyzer Use currying Interpreter: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. 59
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) )))) 60
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))))) 61
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)))))) 62
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)))) 63
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. 64
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)) 65
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)))))) 66
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)))))) 67
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... ))))) 68
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... ))))) 69
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 =) | | | # | | | (analyze n) | | | # | | | (analyze 1) | | | # | | |# // returned from analyze '(= n 1) 70
71
| | |(analyze 1) | | |# | | |(analyze (* (factorial (- n 1)) n)) | | | (analyze *) | | | # | | | (analyze (factorial (- n 1))) | | | |(analyze factorial) | | | |# | | | |(analyze (- n 1)) | | | | (analyze -) | | | | # | | | | (analyze n) | | | | # | | | | (analyze 1) | | | | # | | | |# // returned from analyze '(- n 1) | | | # // returned from analyze '(factorial (- n 1)) | | | (analyze n) 71
72
No repeated analysis - example | | | # | | |# // returned from analyze '( * (factorial... | | # // returned from analyze '(if... | |# // returned from analyze '(lambda... | # // 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) | |# // returned from analyze 'factorial | |(analyze 4) | |# // returned from analyze 4 | # // returned from analyze '(factorial 4) |24// returned from application on the-global-environment // no recursive analysis when recursive analyzed procedure is applied!! 72
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. 73
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.