Presentation is loading. Please wait.

Presentation is loading. Please wait.

Rehearsal: Lazy Evaluation Infinite Streams in our lazy evaluator

Similar presentations


Presentation on theme: "Rehearsal: Lazy Evaluation Infinite Streams in our lazy evaluator"— Presentation transcript:

1 Rehearsal: Lazy Evaluation Infinite Streams in our lazy evaluator
Lecture 22 Rehearsal: Lazy Evaluation Infinite Streams in our lazy evaluator

2 We’ll write a lazy interpreter.
Our machine language is regular Scheme. I.e., it runs in applicative order, and it’s not lazy except for special cases. We will write a lazy interpreter, that translates the input code to instructions for the Non-lazy machine.

3 Thunks Abstractly – a thunk is a "promise" to return a value when later needed ("forced") Concretely – our representation: thunk env exp

4 Thunks- implementation
env exp (define (delay-it exp env) (list 'thunk exp env)) (define (thunk? obj) (tagged-list? obj 'thunk)) (define (thunk-exp thunk) (cadr thunk)) (define (thunk-env thunk) (caddr thunk))

5 Forcing a thunk. (define (force-it obj) (cond ((thunk? obj)
(actual-value (thunk-exp obj) (thunk-env obj))) (else obj))) (define (actual-value exp env) (force-it (l-eval exp env)))

6 L-apply Notice that l-apply sends all arguments of
(define (l-apply procedure arguments env) (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)))) Notice that l-apply sends all arguments of Compound procedures to sleep.

7 L-Eval Undelying procedures (like eval-definition)
(define (l-eval exp env) (cond ((self-evaluating? exp) exp) ((variable? exp) (lookup-variable-value exp env)) ((quoted? exp) (text-of-quotation exp)) ((assignment? exp) (eval-assignment exp env)) ((definition? exp) (eval-definition exp env)) ((if? exp) (eval-if exp env)) ((lambda? exp) (make-procedure (lambda-parameters exp) (lambda-body exp) env)) ((begin? exp) (eval-sequence (begin-actions exp) env)) ((cond? exp) (l-eval (cond->if exp) env)) ((application? exp) (l-apply (actual-value (operator exp) env) (operands exp) (else (error "Unknown expression type – l-EVAL" exp)))) Undelying procedures (like eval-definition) call l-eval instead of eval. This is a top down, modular piece of software, built correctly with many layers of abstraction. However, since you havn’t built an interpreter before, we will not start directly a top down review of the process but rather first give a simplified example. Note that the use of a high level description in the main eval loop allows easy modification For possible changes to the language, but also makes it harder to add new constructs since they must Be added by changing this main eveal loop. L-eval does not wake up the arguments.

8 List-of-arg-values, list-of-delayed-args
(define (list-of-arg-values exps env) (if (no-operands? exps) '() (cons (actual-value (first-operand exps) env) (list-of-arg-values (rest-operands exps) env)))) (define (list-of-delayed-args exps env) (if (no-operands? exps) '() (cons (delay-it (first-operand exps) env) (list-of-delayed-args (rest-operands exps) env))))

9 Let’s take an example (define d1 (delay-it exp env)) thunk env exp
d1 is a pointer to a list. Exp is an abstract expression, and it is not evaluated.

10 What does l-eval do with a thunk?
env exp answer It returns the address of d1, I.e., a pointer to the list. Exp is an abstract expression, and it is not evaluated.

11 What does force-it do with a thunk?
env exp (force-it d1) (actual-value exp env) It evalutes exp in the environment env.

12 Taking a bigger example: infinite streams
We want to work with non-strict cons, car, cdr. We work with our lazy evaluator Running over the non-lazy Scheme. We define: (define (cons x y) (lambda (m) (m x y))) (define (car z) (z (lambda (p q) p))) (define (cdr z) (z (lambda (p q) q)))

13 Our example; the ones stream.
(define ones (cons 1 ones)) (car ones) We will do it in detail. We will be so tired after that, that we won’t need more examples… And we will also be running out of time…

14 So we start… The outer loop gets the input: exp=
“(define ones (cons 1 ones))” It calls: (actual-value ‘(define ones (cons 1 ones)) GE) The actual-value from the outer loop, is the one sending the force, which wakes up all the sleeping values that are needed. It calls: (force-it (l-eval ‘(define ones (cons 1 ones)) GE))

15 It’s a definition, so… (force-it (eval-definition
‘(define ones (cons 1 ones)) GE)) (force-it (define-variable! (definition-variable ‘(define..)) (l-eval (definition-value ‘(define ..)) GE) GE)) (force-it (define-variable! ‘ones (l-eval ‘(cons 1 ones) GE) GE))

16 Eval again, and it’s … a procedure
(force-it (define-variable! ‘ones (l-apply (actual-value ‘cons GE) ‘(1 ones) GE)) (actual-value ‘cons GE) (force-it (l-eval ‘cons GE)) (force-it #proc-..) #proc-.. (force-it (define-variable! ‘ones (l-apply #proc-cons ‘(1 ones) GE)) GE))

17 L-apply gets into action…
(force-it (define-variable! ‘ones (l-eval-sequence ((lambda (m) (m x y))) (extend-environment ‘(x y) (list-of-delayed-args ‘(1 ones) GE) GE))

18 The whole point: the arguments are delayed.
(force-it (define-variable! ‘ones (l-eval-sequence ((lambda (m) (m x y))) (extend-environment ‘(x y) (list (delay-it ‘1 GE) (delay-it ‘ones GE)) GE))

19 I.e., the arguments are thunks.
(force-it (define-variable! ‘ones (l-eval (lambda (m) (m x y)) (extend-environment ‘(x y) (list (list 'thunk ‘1 GE) (list ‘thunk ‘ones GE)) GE))

20 L-eval again. This time.. A procedure
(force-it (define-variable! ‘ones (make-procedure (lambda-parameters ‘(lambda (m) (m x y))) (lambda-body ‘(lambda (m) m x y))) (extend-environment ‘(x y) (list (list 'thunk ‘1 GE) (list ‘thunk ‘ones GE)) GE))

21 So.. We create the new environment We make the procedure
We assign the procedure value to the variable ‘ones in GE define-variable! Returns ‘ok It’s not a thunk so force-it returns it as well. GE E1 x: (list 'thunk ‘1 GE) y: (list ‘thunk ‘ones GE)) ones: p: m body: (m x y)

22 Now we try ‘(car ones) (actual-value ‘(car ones) GE)
(force-it (l-eval ‘(car ones) GE)) (force-it (l-apply #proc-car ‘ones GE)) (force-it (l-eval-sequence ‘((z (lambda (p q) p))) (extend-environment ‘(z) (list-of-delayed-args ‘ones GE) GE)))

23 L-eval gets ready.. (force-it (l-eval ‘(z (lambda (p q) p))
(extend-environment ‘(z) (list (list 'thunk ‘ones GE)) GE))) l-eval looks at the expression, and it’s a compound procedure.

24 L-eval moves (force-it (l-eval (l-apply
(actual-value ‘z (extend-env ..)) ‘(lambda (p q) p) (extend-environment ‘(z) (list (list 'thunk ‘ones GE)) GE)))

25 (actual-value ‘z (extend-env ..))
Actual-value opens to: (force-it (l-eval ‘z (extend-environment ‘(z) (list (list 'thunk ‘ones GE)) GE))) (force-it (list ‘thunk ‘ones GE)) (actual-value ‘ones GE) It is NOT a thunk, so we get: ones the address of The procedure ones.

26 Back to L-eval (force-it (l-eval (l-apply ones ‘(lambda (p q) p)
(extend-environment …))) We move the ball to l-apply…

27 L-eval again.. (force-it (l-eval (l-eval ‘(m x y) (extend-environment
(list-of-delayed-args ‘(lambda (p q) p) (extend-env…)) ‘(x y) (list (list 'thunk ‘1 GE) (list ‘thunk ‘ones GE)) GE)))))) E2

28 And l-eval again… L-eval gets into action. It calls:
(l-apply (actual-value (operator exp) E2) … This forces m, and assigns m the procedure (lambda (p q) p) At this stage x,y are still delayed. We now get: (l-apply (lambda (p q) p) ‘(x y) E2)

29 And l-apply again… (l-eval ‘p (extend-environment ‘(p q)
(list-of-delayed-args ‘(x y) E2) E2)) In the extended environment E2, p gets bounded to (list ‘thunk x E1) And so this is what l-eval returns. (list ‘thunk x E1)

30 We know force it. Obj = (list ‘thunk x E1)
(actual-value (thunk-exp obj) (thunk-env obj))) (actual-value x E1) (force-it (l-eval x E1)) (force-it (list ‘thunk ‘1 GE)) ‘1 We had to force the object twice!

31 Add-lists and the integers
Now consider: (define (add-lists list1 list2) (cond ((null? List1) list2) ((null? List2) list1) (else (cons (+ (car list1) (car list2)) (add-lists (cdr list1) (cdr list2)))))) (define ones (cons 1 ones)) (define integers (cons 1 (add-lists one integers))

32 Upper vs. lower language
Try to figure out what happens in the lower level with the Integers example. It is very difficult for humans to think in machine-language It is impossible for machines to think in upper language The interpreter (compiler) bridges the gap.

33 And another moral: it pays off to program well
The actual process that takes place when evaluating integers, Is techniquly complicated. A process can be techniqly complicated but still (very) efficient. With careful planning, complicated processes can have a Short, Concise Efficient implementation as a sequence of simple well-defined procedures.


Download ppt "Rehearsal: Lazy Evaluation Infinite Streams in our lazy evaluator"

Similar presentations


Ads by Google