מבוא מורחב למדעי המחשב תרגול 13

1 / 29

# מבוא מורחב למדעי המחשב תרגול 13 - PowerPoint PPT Presentation

מבוא מורחב למדעי המחשב תרגול 13. Lazy Evaluation. Lazy Evaluation Implementation. Two types of values Delayed Values Actual Values Introduce two functions (actual-value exp env ) returns real value (delay-it exp env ) returns a “ thunk ”. Lazy Evaluation.

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

## PowerPoint Slideshow about ' מבוא מורחב למדעי המחשב תרגול 13' - manchu

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

### מבוא מורחב למדעי המחשבתרגול 13

Lazy Evaluation

Lazy Evaluation Implementation
• Two types of values
• Delayed Values
• Actual Values
• Introduce two functions
• (actual-value exp env)returns real value
• (delay-it exp env)returns a “thunk”
Lazy Evaluation
• Normal order - delay operands (only)
• Special forms and compound procedures may return delayed objects
• (l-eval exp env) may return delayed value
• We use actual-value only if we have to, otherwise we use l-eval
• Primitives must receive the actual value
• Print-on-screen is actual value
Lazy Evaluation – l-eval

(define (l-eval exp env)

(cond ((self-evaluating? exp) exp)

...

((application? exp

(l-apply (actual-value (operator exp) env)

(operands exp)

env))

(else (error "Unknown expression" exp))))

Compare with mc-eval:

((application? exp)

(mc-apply (mc-eval (operator exp) env)

(list-of-values (operands exp) env)))

Lazy Evaluation – l-apply

(define (l-apply procedure arguments env) ; changed

(cond ((primitive-procedure? procedure)

(apply-primitive-procedure

procedure

(list-of-arg-values arguments env)))

((compound-procedure? procedure)

(l-eval-sequence

(procedure-body procedure)

(extend-environment

(procedure-parameters procedure)

(list-of-delayed-args arguments env)

(procedure-environment procedure))))

(else (error "Unknown proc" procedure))))

Actual vs. Delayed Values

(define (actual-value exp env)

(force-it (l-eval exp env)))

(define (list-of-arg-values expsenv)

(if (no-operands? exps) \'()

(cons (actual-value (first-operand exps) env)

(list-of-arg-values (rest-operands exps)

env))))

(define (list-of-delayed-argsexpsenv)

(if (no-operands? exps) \'()

(cons (delay-it (first-operand exps) env)

(list-of-delayed-args (rest-operands exps)

env))))

thunk

exp

env

Representing Thunks
• In our implementation we represent “Thunks” using a tagged list:
Thunks – abstraction

Constructor:

(define (delay-it exp env) (list \'thunk exp env))

Selectors:

(define (thunk? obj) (tagged-list? obj \'thunk))

(define (force-it obj)

(cond ((thunk? obj)

(actual-value (thunk-exp obj)

(thunk-envobj)))

(else obj)))

Lazy Evaluation – other changes needed
• Example – need actual predicate value in conditional if...

(define (l-eval-if exp env)

(if (true? (actual-value (if-predicate exp) env))

(l-eval (if-consequent exp) env)

(l-eval (if-alternative exp) env)))

Might return

delayed values

• Example – don\'t need actual value in assignment...
• (define (l-eval-assignment exp env)
• (set-variable-value!
• (assignment-variable exp)
• (l-eval (assignment-value exp) env)
• env)
• \'ok)

No change relative to

mc-eval version!

Lazy Evaluation – more changes

(define input-prompt ";;; L-Eval input:")

(define output-prompt ";;; L-Eval value:")

(define (driver-loop)

(prompt-for-input input-prompt)

(let ((output (actual-value

input

the-global-environment)))

(cond ((eq? output exit-object)

\'done)

(else

(announce-output output-prompt)

(user-print output)

(driver-loop))))))

Lazy Evaluation - Example
• What happens when this code is executed using mc-eval?
• Can we add “unless” to the metacircular evaluator?

(define (unless condition usual exceptional)

(if condition exceptional usual))

(define (factorial n)

(unless (= n 1)

(* n (factorial (- n 1)))

1))

thunk

exp

env

evaluated-thunk

result

MemoizingThunks
• Only evaluate Thunks once
• Mutate our data structure when the thunk is first evaluated
Thunks – Memoizing Implementation

(define (evaluated-thunk? obj)

(tagged-list? obj \'evaluated-thunk))

(define (thunk-value evaluated-thunk)

(define (force-it obj)

(cond ((thunk? obj)

(let ((result (actual-value (thunk-exp obj)

(thunk-envobj))))

(set-car! obj \'evaluated-thunk)

(set-car! (cdrobj) result)

(set-cdr! (cdrobj) \'())

result))

((evaluated-thunk? obj) (thunk-value obj))

(else obj)))

Timing Comparison
• How would the different implementations (mc-eval, lazy, lazy + memoization) compute the following:

(define (square x) (* x x))

(square (fib 100))

Example
• What is the result of (func 1)?
• Is it similar to evaluation with mc-eval?

(define (func x)

(define (p e)

e

x)

(p (set! x (cons x \'(2)))))

lazy and lazy-memo
• We want to extend the original mc-eval:

(lambda (a (b lazy) c (d lazy-memo)) ...)

• "a", "c" are strict variables (evaluated before procedure application
• "b" is lazy; it gets (re)-evaluated each time its value is actually needed
• "d" is lazy-memo; it gets evaluated the first time its value is needed, and then that value is returned again any other time it is needed again.

when

forced

evaluated-thunk

result

Controllably Memo-izing Thunks
• thunk – never gets memoized
• thunk-memo – first eval is remembered
• evaluated-thunk – memoized-thunk that has already been evaluated

Thunk

Memo

exp

env

A new version of delay-it
• Look at the variable declaration to do the right thing...

(define (delay-it decl exp env)

(cond ((not (declaration? decl))

(l-eval exp env))

((lazy? decl)

(list \'thunk exp env))

((memo? decl)

(list \'thunk-memo exp env))

(else (error "unknown declaration:" decl))))

Changes to force-it

(define (force-it obj)

(cond ((thunk? obj) ;eval, but don\'t remember it

(actual-value (thunk-exp obj)

(thunk-env obj)))

((memoized-thunk? obj) ;eval and remember

(let ((result

(actual-value (thunk-exp obj)

(thunk-env obj))))

(set-car! obj \'evaluated-thunk)

(set-car! (cdr obj) result)

(set-cdr! (cdr obj) \'())

result))

((evaluated-thunk? obj) (thunk-value obj))

(else obj)))

Changes to l-apply
• Key: in l-apply, only delay "lazy" or "lazy-memo" params
• make thunks for "lazy" parameters
• make memoized-thunks for "lazy-memo" parameters

(define (l-apply procedure arguments env)

(cond ((primitive-procedure? procedure)

...) ; as before; apply on list-of-arg-values

((compound-procedure? procedure)

(l-eval-sequence

(procedure-body procedure)

(let ((params (procedure-parameters procedure)))

(extend-environment

(map parameter-name params)

(list-of-delayed-argsparamsarguments env)

(procedure-environment procedure)))))

(else (error "Unknown proc" procedure))))

Deciding when to evaluate an argument...
• Process each variable declaration together with application subexpressions – delay as necessary:

(define (list-of-delayed-argsvar-declsexpsenv)

(if (no-operands? exps)

\'()

(cons (delay-it (first-variable var-decls)

(first-operand exps)

env)

(list-of-delayed-args

(rest-variables var-decls)

(rest-operands exps)env))))

Syntax Extensions – Parameter Declarations

(define (first-variable var-decls) (car var-decls))

(define (rest-variables var-decls) (cdr var-decls))

(define declaration? pair?)

(define (parameter-name var-decl)

(if (pair? var-decl) (car var-decl) var-decl))

(define (lazy? var-decl)

(and (pair? var-decl) (eq? \'lazy (cadr var-decl))))

(define (memo? var-decl)

(and (pair? var-decl)

Exam Question
• Assume we have the following special form:
• (static <variable> <value>)
• Evaluation
• If <variable> exists in the global environment, do nothing
• Otherwise evaluate <value> in the current environmentand bind <variable> to the result of the evaluation in the global environment

> (define (f) (static x 1) x)

> (define (g x) (static x (* 2 2)) x)

> (g 7)

> (f)

> (set! x (+ x 1))

> (f)

7

4

5

How would the code evaluate?

(define (id x)

(static counter 0)

(set! counter (+ counter 1))

x)

(define (foobar counter)

(id (begin (static counter 5)

(id counter))))

(foobar 10)

counter

mc-eval, static binding

GE

id:

foobar:

counter:5

/6

/7

E3

E2

E1

counter:10

x:10

p:xb:…

p:counterb:…

x:10

(foobar 10)

10

counter

7

l-eval, static binding

GE

id:

foobar:

counter:0

/1

/2

E3

E1

E2

counter:10

thunk

x:

p:xb:…

p:counterb:…

(begin…)

x:10

(foobar 10)

10

counter

2

In (driver-loop):

(let ((output (actual-value

input

the-global-environment)))

mc-eval, dynamic binding

GE

id:

foobar:

counter:5

E1

E2

E3

XX 11

XX 12

counter:10

x:10

x:10

p:xb:…

p:counterb:…

(foobar 10)

10

counter

5

l-eval, dynamic binding

GE

id:

foobar:

counter:0

E1

E2

E3

XX 11

XX 12

counter:10

thunk

x:

x:11

p:xb:…

p:counterb:…

(begin…)

(foobar 10)

11

In (driver-loop):

(let ((output (actual-value

input

the-global-environment)))

counter

0