Download Evaluators for Functional Programming

Document related concepts
no text concepts found
Transcript
Evaluators for Functional
Programming
Evaluators for Functional Programming
1
How to describe (specify) a
programming language?
1. Syntax: atoms, primitives, combination and
abstraction means.
2. Semantics: values, types.
3. Operational semantics: evaluation rules,
evaluator algorithm.
Evaluators for Functional Programming
2
Evaluator for Functional Programming
• meta-circular :
– Interpreted language = our flavor of Scheme
–(embedding) language = Scheme
• We will see three evaluators for FP:
1. Substitution evaluator (impl. applicativeeval)
2. Environment-based evaluator
(uses an environment data structure)
3. Environment-based compiler
Evaluators for Functional Programming
3
Evaluator Structure
evaluator
program in
interpreted
language
eval
(Global)
Environment
substitute reduce
Value from
interpreted
language
values
written in Implementation (embedding) language
Evaluators for Functional Programming
4
common evaluator structure
evaluator
program in
interpreted
language
(Global)
Environment
abstract
syntax
parser
parsed
expression
(parse tree)
eval
substitute reduce
Evaluators for Functional Programming
Value from
interpreted
language
values
5
basic compiler structure
program in
interpreted
language
Value from
target
language
values
compiler
abstract
syntax
parser
parsed
expression
(parse tree)
compilation
execution/
evaluation
program in
target
language
Evaluators for Functional Programming
Global
Environment
6
evaluator structure
evaluator
Scheme
expression
(Global)
Environment
Code in:
Racket-Evaluators\substitution-interpreter\
Evaluators for Functional Programming
Value
7
Input
• Input: a scheme expression or an already evaluated
scheme expression (in case of repeated evaluation).
(lambda (lst) (car (car lst))
• Input is accepted in the form of constant lists.
'(lambda (lst) (car (car lst)))
(list 'lambda (list 'lst) (list 'car (list 'car
'lst))
• uniformity of Scheme expressions and the printed
form of lists.
Evaluators for Functional Programming
8
Input
> (derive-eval '(+ 1 2) )
3
> (derive-eval
(list 'lambda (list 'lst) (list 'car (list 'car
'lst)) ))
(procedure (lst) ((car (car lst))))
> (derive-eval '(lambda (lst) (car (car 'lst))) )
(procedure (lst) ((car (car lst))))
> (derive-eval (lambda (lst) (car (car lst)) ))
. . ASP.scm:247:31: car: expects argument of type
<pair>; given #<procedure>
Evaluators for Functional Programming
9
Abstract Syntax Parser (ASP)
A tool that
1. Identifies the kind of an input expression (atomic,
lambda, application, etc)
2. Select the components of a Scheme expression
3. Construct a Scheme expression from its
components
Impl. an interface for Scheme Expression, according to
Abstract Syntax of Scheme: ADT!
Evaluators for Functional Programming
10
Derived Expressions
Language expression have two classes:
• Kernel (core knows what to do with them)
• Derived (rewritten using kernel expressions –
more on that later)
Evaluators for Functional Programming
11
Tagged-data interface and impl.
Evaluators for Functional Programming
12
Tagged-data interface and impl.
Evaluators for Functional Programming
13
Parser procedures - atomic exp.
Evaluators for Functional Programming
14
Parser procedures - compound exp.
Evaluators for Functional Programming
15
Parser procedures - compound exp.
Evaluators for Functional Programming
16
Parser procedures - compound exp.
Evaluators for Functional Programming
17
Parser procedures - compound exp.
Evaluators for Functional Programming
18
Parser procedures - compound exp.
Evaluators for Functional Programming
19
Parser procedures - compound exp.
Evaluators for Functional Programming
20
Parser procedures - compound exp.
Evaluators for Functional Programming
21
Parser procedures - compound exp.
letrec - similar functions...
Evaluators for Functional Programming
22
Parser procedures - compound exp.
Evaluators for Functional Programming
23
Parser procedures - application
• The application expression is special compound expression: It
does not have a tag.
Evaluators for Functional Programming
24
ASP - Derived Expressions
'derived' expression
are translated into 'core' expressions
(according to syntactic sugar/macro rule),
before being evaluated.
Derivation procedures are part of the ASP
; Signature: derive(exp)
; Type: [Scheme-exp -> Scheme-exp]
Evaluators for Functional Programming
25
ASP - Derived Expressions
(let ((x (+ y 2))
(y (- x 3)))
(* x y))
((lambda (x y)
(* x y))
(+ y 2)
(- x 3))
(define let->combination
(lambda (exp)
(let ((vars (let-variables exp))
(body (let-body exp))
(initial-vals (let-initial-values exp)))
(make-application (make-lambda vars body)
initial-vals))))
Evaluators for Functional Programming
26
ASP - Derived Expressions
(define (f x y)
(display x)
(+ x y))
(define f
(lambda (x y)
(display x)
(+ x y)))
(define function-define->define
(lambda (exp)
(let ((var (function-definition-variable exp))
(params (function-definition-parameters exp))
(body (function-definition-body exp)))
(make-definition var (make-lambda params body)))))
Evaluators for Functional Programming
27
ASP - Derived Expressions
(cond ((> x 0) x)
((= x 0) (display ’zero) 0)
(else (- x)))
(if (> x 0)
x
(if (= x 0)
(begin (display ’zero) 0)
(- x)))
• cond->if
Evaluators for Functional Programming
28
ASP - Derived expressions
(cond ((> x 0) x)
(else (cond ((= x 0) 0)
(else (- x))))))
shallow derivation
(if (> x 0)
x (cond ((= x 0) 0)
(else (- x))))
deep (recursive)
derivation
(if (> x 0)
x (if(= x 0)
0
(- x)))
Evaluators for Functional Programming
29
ASP - Derived expressions
(let*((x 10)
(y (+ x 2))
(+ x y))
shallow derivation
(let((x 10))
(let ((y (+ x 2)))
(+ x y)))
recursive derivation until
fixed point achieved
((lambda(x) (let ((y ....))
10)
Evaluators for Functional Programming
30
Evaluators for Functional Programming
31
Evaluators for Functional Programming
32
evaluator structure
evaluator
Scheme
expression
(Global)
Environment
Code in:
Racket-Evaluators\substitution-interpreter\
Evaluators for Functional Programming
Value
33
Applicative-Eval Evaluator Core
data structures:
1. Evaluated values
2. The global environment
– managing "global" variable-value bindings.
Evaluators for Functional Programming
34
Evaluated Values
• Repeated evaluation of compound values:
applicative-eval[((λ (lst)(car lst)) (list 1 2 3))]
applicative-eval[(λ (lst)(car lst))]
<== <Closure (lst)(car lst) >
applicative-eval[(list 1 2 3)]
<== (1 2 3)
// evaluated value of list
applicative-eval[ (car (1 2 3)) ] ==>
applicative-eval[car]
<== Code of car.
applicative-eval[(1 2 3)]
<== "error: 1 is not a procedure"
• Same problem for values of lambda, quote (and other
possible compound values) and primitive procedures.
• Need to identify (tag), evaluated values.
Evaluators for Functional Programming35
Evaluated values ADTs
Primitive-procedure
Procedure
Other
make-primitive-procedure [T -> Primitive-procedure]
primitive-procedure?
[T –> Boolean]
primitive-implementation [Primitive-procedure –> T]
make-procedure
[LIST(Symbol)*LIST –> Procedure]
compound-procedure?
procedure-parameters [Procedure –> LIST(Symbol)]
procedure-body
[Procedure –> LIST]
make-value
value?
value-content
Evaluators for Functional Programming
36
Primitive procedure - Impl.
Evaluators for Functional Programming
37
Procedure - Impl.
Evaluators for Functional Programming
38
evaluator structure
evaluator
Scheme
expression
(Global)
Environment
Code in:
Racket-Evaluators\substitution-interpreter\
Evaluators for Functional Programming
Value
39
The global environment
GE procedures:
Evaluators for Functional Programming
40
The global environment
• mutable binding management.
mapping from "global" variables to values.
• make-binding
• binding-variable
• Binding-value
Evaluators for Functional Programming
41
evaluator structure
evaluator
Scheme
expression
(Global)
Environment
Code in:
Racket-Evaluators\substitution-interpreter\
Evaluators for Functional Programming
Value
42
Applicative-Eval Evaluator - core
•
•
•
•
•
•
•
Implementation of applicative eval algorithm.
Derives expressions
Special form/Atomic/Application
Application: Eval-substitute-reduce (recursive).
Has 'rename' and 'substitute' sub-routines
Uses: ASP (parser), GE packages
Creates Evaluated Values and returns them.
Evaluators for Functional Programming
43
Applicative-Eval Evaluator - core
Evaluators for Functional Programming
44
Applicative-Eval Evaluator - core
Evaluators for Functional Programming
45
Applicative-Eval Evaluator - core
Evaluators for Functional Programming
46
Applicative-Eval Evaluator - core
atomic exp.
Evaluators for Functional Programming
47
Applicative-Eval Evaluator - core
special forms
Evaluators for Functional Programming
48
Applicative-Eval Evaluator - core
special forms
Evaluators for Functional Programming
49
Applicative-Eval Evaluator - core
special forms
Evaluators for Functional Programming
50
Applicative-Eval Evaluator - core
application
Evaluators for Functional Programming
51
Applicative-Eval Evaluator - core
primitive procedure application
Evaluators for Functional Programming
52
Applicative-Eval Evaluator - core
substitution
Evaluators for Functional Programming
53
evaluator structure
evaluator
Scheme
expression
(Global)
Environment
Code in:
Racket-Evaluators\substitution-interpreter\
Evaluators for Functional Programming
Value
54
Applicative-Eval Evaluator - tests
> (derive-eval '(* 3 4))
'(value 12)
> (derive-eval '((lambda (f) (f 2 1)) +))
'(value 3)
Regression tests:
(test (derive-eval '(* 3 4)) => '(value 12))
(test (derive-eval '(cons 3 (cons 4 (list)))) => '(value
(3 4)))
(test (derive-eval '((lambda (f) (f 2 1)) +)) => '(value
3))
(test (derive-eval '(begin 1 2 3)) => '(value 3))
(test (derive-eval '(begin 1 2 3)) => '(value 3))
(test (derive-eval '(define x 2)) => 'ok)
(test (derive-eval '(define (f x) (+ x x))) => 'ok)
(test (derive-eval 'x) => '(value 2))
(test (derive-eval '(f x)) => '(value 4))
(test (derive '(let ((x 1)) (+ x 1))) =>
'(
(lambda (x)(+ x 1)) 1))
Evaluators for Functional Programming
55
The environment-based
operational semantics
56
Why Substitute?
• Because we needed the values of the
variables.
57
Ok, So What’s Wrong with
Substitution?
• On every application we have to:
– Rename
– Substitute
– Analyze the body (ask what kind of expression it is
etc)
• Mixed value/expression. Evaluator value
distinction required
58
New Way to get the Value of a
Variable: The Environment Model
59
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.
60
The Environments Model
Substitution model: a single global environment
Environment Table
Name
score
Value
23
Environments model: many environments.
61
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
A
x: 15
y:
2
1
62
Environment: a finite 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)
B
E2
z: 10
this arrow is called
the enclosing
environment pointer
A
E1
x: 15
y:
1
63
2
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
64
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=<f1, f2,..., fn>.
environment diagram
65
Operations on environments and frames:
66
Operations on environments and frames:
67
Operations on environments and frames:
68
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.
69
The closure data structure
• A closure carries an environment - the one containing all local
variables defined when it was created.
>(define f
B
(let ((x 3)) 1
(lambda(y) (+ x y)))
>(f 1)
B2
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.
70
Double bubble: how to draw a
procedure
(lambda (x) (* x x))
#[proc-...]
Environment
pointer
A compound proc
that squares its
argument
Code pointer
parameters: x
body: (* x x)
71
The Environment Model Evaluation Algorithm
72
The Environment Model Evaluation Algorithm continued
73
The Environment Model Evaluation Algorithm continued
74
The Environment Model Evaluation Algorithm continued
75
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`
76
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.
77
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)
78
Example 4.5.
79
Example 4.6.
80
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 runtime
• 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
81
dynamic-env-eval
82
Example 4.6.
• Not all evaluation algorithms are equivalent! dynamic-eval != env-eval
(compute the same function, have the same domain)
83
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
84
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
85
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)))
86
evaluator structure
evaluator
Scheme
expression
(Global)
Environment
Value
Chapter 4 - Evaluators for Functional
Programming
87
Files
Racket-Evaluators\env-functional-interpreter-compiler>dir
analyzer-core.rkt
analyzer-tests.rkt
env-ds.rkt
interpreter-core.rkt
interpreter-tests.rkt
88
4.4.2 Data Structures Package
4.4.2.1 Procedure ADTs and their implementation
• Primitive procedure: same as in applicative-eval.
89
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
90
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
91
4.4.2.2 Environment related ADTs and their
implementations:
• The interpreter holds a "DrRacket" variable
the-global-environment
* Bindings, Frames, Environments.
92
4.4.2.2 Environment related ADTs and their implementations:
The Binding ADT and its implementation:
binding
var
val
Alternative definition:
(define
(define
(define
What is
make-binding cons)
binding-variable car)
binding-value cdr)
the difference?
93
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 …)))))
94
4.4.2.2 Environment implementation
• An environment is implemented as a list of boxed (mutable) frames.
Racket box operations
box(x)
unbox(b)
set-box!(b, y)
environment
box
frame
substitution
frame
substitution
* in implementation language
frame
substitution
variable->value lookup function
95
4.4.2.2 Global environment construction
96
97
(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)))))
98
(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)))))
99
; 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)))))
100
4.4.1.1 Main evaluator loop:
101
102
103
4.4.1.2 Evaluation of atomic expressions
104
105
106
107
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))))
Primitive procedure application
109
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)
110
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.
111
Files
Racket-Evaluators\env-functional-interpreter-compiler>dir
analyzer-core.rkt
analyzer-tests.rkt
env-ds.rkt
interpreter-core.rkt
interpreter-tests.rkt
112
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.
113
analyzer structure
Scheme
expression
code in the
implementation
language.
syntax-analysis
(compilation)
Program in
target
language
(Global)
Environment
run-time
evaluation
Value
Chapter 4 - Evaluators for Functional
Programming
114
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 datastructure manipulation).
• means: curried function style.
115
An Environment-based FP Meta-Circular Compiler
The analyzer
• Use currying
Interpreter:
Compiler:
(lambda (exp env)
(lambda (exp)
syntax analysis+
run-time evaluation
syntax analysis
(performed once)
returns
(lambda(env)
[Expression*Env->T]
run-time evaluation
[Expression->[Env->T]]
• Compiler output is code in the implementation language.
116
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 'eval "unknown expression type: ~s"
exp)))))
117
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)))))
118
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))))))
119
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))))
120
Environment-based compiler
(define analyze-sequence
(lambda (exps)
(let ((procs (map analyze exps)))
(lambda (env)
(let ((vals (map (lambda (proc) (proc env)) procs)))
(last vals))))))
• relies on the order of map in the underlining
(implementation) Scheme.
121
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))
122
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))))))
123
• 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))))))
124
• 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 ... )))))
125
• Compiler - evaluation of analyzed operator on extended environment
(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)))
(body new-env)))
(else (error 'apply "unknown procedure type: ~s" procedure)))))
126
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)
127
| | |(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)
| | | #<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
128
No repeated analysis - example
> (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-globalenvironment
// no recursive analysis when recursive analyzed procedure is
applied!!
129
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.
130
Related documents