340 likes | 351 Views
This lecture explores the concept of lazy evaluation in computer science and its benefits. It discusses how expressions are evaluated, the advantages of lazy evaluation, and provides examples to illustrate its use. The lecture also touches on the idea of metalinguistic abstraction and introduces the concept of changing the language to alter behavior.
E N D
Lecture 26: In Praise of Idleness David Evans http://www.cs.virginia.edu/evans CS200: Computer Science University of Virginia Computer Science
Menu • Implementing Environments • PS8 Demo • Lazy Scheme CS 200 Spring 2003
Environmental Model of Evaluation • To evaluate a combination, evaluate all the subexpressions and apply the value of the first subexpression to the values of the other subexpressions. • To apply a compound procedure to a set of arguments, evaluate the body of the procedure in a new environment. The parent of the new environment is the procedure’s environment; the frame is a new frame that contains places with the formal parameters bound to the arguments. CS 200 Spring 2003
mapply (define (mapply procedure operands) (cond ((primitive-procedure? procedure) (apply-primitive procedure operands)) ((compound-procedure? procedure) (meval-sequence (procedure-body procedure) (extend-environment (procedure-parameters procedure) operands (procedure-environment procedure)))) (else (error “Can’t apply: " procedure)))) CS 200 Spring 2003
Representing Environments An environment is a frame and a parent. 4 x : (define (make-new-environment frame env) (cons frame env)) (define (first-frame env) (car env)) (define (enclosing-environment env) (cdr env)) CS 200 Spring 2003
Representing Frames A frame is a list of name-value pairs. 3 y : 4 x : (define (make-empty-frame) (list)) CS 200 Spring 2003
extend-environment (define (extend-environment names values env) (make-new-environment (map (lambda (name value) (cons name value)) names values) env)) CS 200 Spring 2003
meval (define (meval expr env) (cond ((self-evaluating? expr) expr) ((variable? expr) (environment-lookup-name expr env)) ((lambda? expr) (make-procedure (lambda-parameters expr) (lambda-body expr) env)) ((application? expr) (mapply (meval (application-operator expr) env) (map (lambda (subexpr) (meval subexpr env)) (application-operands expr)))) (else (error "Unknown expression: " exp)))) CS 200 Spring 2003
environment-lookup-name (define (environment-lookup-name name env) (if (null? env) (error "No binding " name) (if (frame-contains? name (first-frame env)) (frame-lookup-name name (first-frame env)) (environment-lookup-name name (enclosing-environment env))))) (define (frame-lookup-name name frame) (if (null? frame) (error "Name not found:" name) (if (eq? (car (car frame)) name) (cdr (car frame)) (frame-lookup-name name (cdr frame))))) CS 200 Spring 2003
Metalinguistic Abstraction Now we know how to implement a Scheme evaluator, we can change the language to make it behavior differently • PS7: • Add new special forms (quist, observe) • Add new kinds of data (quist’s) for which applications are evaluated differently • Today: • Change how expressions are evaluated • Next week: • Add type checking to catch programming errors CS 200 Spring 2003
Lazy Evaluation • Don’t evaluate expressions until their value is really needed. • We might save work this way, since sometime we don’t need the value of an expression • We might change the meaning of some expressions, since the order of evaluation matters • Not a wise policy for problem sets (the values will always be needed!) CS 200 Spring 2003
Lazy Examples > (meval ‘((lambda (x) 3) (* 2 2)) the-global-environment) 3 > (lazeval ‘((lambda (x) 3) (* 2 2)) the-global-env) 3 > (meval ‘((lambda (x) 3) (* 2 2)) (car 3)) error – can’t take car of 3 > (lazeval ‘((lambda (x) 3) (car 3)) the-global-env) 3 > (meval ‘((lambda (x) 3) (loop-forever)) the-global-env) no value – loops forever > (lazeval ‘((lambda (x) 3) (loop-forever)) the-global-env) 3 laziness can be useful! CS 200 Spring 2003
Ordinary men and women, having the opportunity of a happy life, will become more kindly and less persecuting and less inclined to view others with suspicion. The taste for war will die out, partly for this reason, and partly because it will involve long and severe work for all. Good nature is, of all moral qualities, the one that the world needs most, and good nature is the result of ease and security, not of a life of arduous struggle. Modern methods of production have given us the possibility of ease and security for all; we have chosen, instead, to have overwork for some and starvation for others. Hitherto we have continued to be as energetic as we were before there were machines; in this we have been foolish, but there is no reason to go on being foolish forever. Bertrand Russell, In Praise of Idleness, 1932 (co-author of Principia Mathematica, proved wrong by Gödel’s proof) CS 200 Spring 2003
PS8 Demo: R U Like Me?Rachel Dada, Grace Deng, Jacques Fourier, Shawn O’Hargan http://www.people.virginia.edu/~brs9e/cs200/home.php3
PS8 Projects • Team requests must be received by 5pm Monday • I will only grant team requests that include a description of your project idea • Remember that you’re projects should be 1 Million times better than last year’s! CS 200 Spring 2003
How do we make our evaluation rules lazier? • To evaluate a combination, evaluate all the subexpressions and apply the value of the first subexpression to the values of the other subexpressions. • To apply a compound procedure to a set of arguments, evaluate the body of the procedure in a new environment. The parent of the new environment is the procedure’s environment; the frame is a new frame that contains places with the formal parameters bound to the argument expressions. When a formal parameter is first used, evaluate the argument expression to get its value. CS 200 Spring 2003
Evaluation of Arguments • Applicative Order (“eager evaluation”) • Evaluate all subexpressions before apply • The standard Scheme rule, Java • Normal Order (“lazy evaluation”) • Evaluate arguments just before the value is needed • Algol60 (sort of), Haskell, Miranda “Normal” Scheme order is not “Normal Order”! CS 200 Spring 2003
meval (define (meval expr env) (cond ((self-evaluating? expr) expr) ((variable? expr) (environment-lookup-name expr env)) ((lambda? expr) (make-procedure (lambda-parameters expr) (lambda-body expr) env)) ((application? expr) (mapply (meval (application-operator expr) env) (map (lambda (subexpr) (meval subexpr env)) (application-operands expr)))) (else (error "Unknown expression: " exp)))) CS 200 Spring 2003
lazeval (define (lazeval expr env) (cond ((self-evaluating? expr) expr) ((variable? expr) (environment-lookup-name expr env)) ((lambda? expr) (make-procedure (lambda-parameters expr) (lambda-body expr) env)) ((application? expr) (lazapply (lazeval (application-operator expr) env) (application-operands expr) env)) (else (error "Unknown expression: " exp)))) CS 200 Spring 2003
lazapply (define (lazapply procedure operands env) (cond ((primitive-procedure? procedure) (apply-primitive procedure operands)) ((compound-procedure? procedure) (lazeval-sequence (procedure-body procedure) (extend-environment (procedure-parameters procedure) operands (procedure-environment procedure)))) (else (error "Unknown applicator: " procedure)))) CS 200 Spring 2003
apply-primitive (define (apply-primitive procedure operands) ;;; The underlying Scheme apply (apply (primitive-procedure-procedure procedure) operands)) (define (lazapply-primitive procedure operands env) ;;; The underlying Scheme apply (apply (primitive-procedure-procedure procedure) (map (lambda (op) (lazeval op env)) operands))) CS 200 Spring 2003
lazeval (define (lazeval expr env) (cond ((self-evaluating? expr) expr) ((variable? expr) (environment-lookup-name expr env)) ((lambda? expr) (make-procedure (lambda-parameters expr) (lambda-body expr) env)) ((application? expr) (lazapply (lazeval (application-operator expr) env) (application-operands expr) env)) (else (error "Unknown expression: " exp)))) CS 200 Spring 2003
lazeval (define (lazeval expr env) (cond ((self-evaluating? expr) expr) ((variable? expr) (lazeval (environment-lookup-name expr env) env)) ((lambda? expr) (make-procedure (lambda-parameters expr) (lambda-body expr) env)) ((application? expr) (lazapply (lazeval (application-operator expr) env) (application-operands expr) env)) (else (error "Unknown expression: " exp)))) CS 200 Spring 2003
Are we lazy? > (lazeval '((lambda (x) (* x x)) 3) the-global-env) 9 > (lazeval '(define loop-forever (lambda () (loop-forever))) the-global-env) ok > (lazeval '((lambda (x) 12) (loop-forever)) the-global-env) 12 > (meval '((lambda (x) ((lambda (x) (+ x x)) x)) 7) the-global-env) 14 > (lazeval '((lambda (x) ((lambda (x) (+ x x)) x)) 7) the-global-env) Doesn’t halt! CS 200 Spring 2003
> (lazeval '((lambda (x) ((lambda (x) (+ x x)) x)) 7) the-global-env) |(lazeval ((lambda (x) ((lambda (x) (+ x x)) x)) 7) (((+ primitive-procedure #<primitive:+>) (* primitive-procedure #<primitive:*>) (- primitive-procedure #<primitive:->)))) | (lazeval (lambda (x) ((lambda (x) (+ x x)) x)) (((+ primitive-procedure #<primitive:+>) (* primitive-procedure #<primitive:*>) (- primitive-procedure #<primitive:->)))) | (procedure (x) (((lambda (x) (+ x x)) x)) (((+ primitive-procedure #<primitive:+>) (* primitive-procedure #<primitive:*>) (- primitive-procedure #<primitive:->)))) | (lazapply (procedure (x) (((lambda (x) (+ x x)) x)) (((+ primitive-procedure #<primitive:+>) (* primitive-procedure #<primitive:*>) (- primitive-procedure #<primitive:->)))) (7) (((+ primitive-procedure #<primitive:+>) (* primitive-procedure #<primitive:*>) (- primitive-procedure #<primitive:->)))) (define (lazeval expr env) (cond ((self-evaluating? expr) expr) ((variable? expr) (lazeval (environment-lookup-name expr env) env)) ((lambda? expr) (make-procedure (lambda-parameters expr) (lambda-body expr) env)) ((application? expr) (lazapply (lazeval (application-operator expr) env) (application-operands expr) env)) (else (error "Unknown expression: " exp)))) CS 200 Spring 2003
Fixing Lazeval • We need to only evaluate things once – the first time we need the value of a name • We need to evaluate them in the correct environment Instead of putting the expression in the frame, make a new kind of object called a thunk that packages the expression with the evaluation environment. The first time we need the value associated with a name, evaluate the thunk and put the value in the name’s place. CS 200 Spring 2003
I thunk I can… (define (make-thunk expr env) (list 'thunk expr env)) (define (thunk? expr) (tagged-list? expr 'thunk)) (define (thunk-expr thunk) (cadr thunk)) (define (thunk-env thunk) (caddr thunk)) CS 200 Spring 2003
thunky lazeval (define (lazeval expr env) (cond ((application? expr) (lazapply (lazeval (application-operator expr) env) (application-operands expr) env)) … CS 200 Spring 2003
thunky lazapply (define (lazapply procedure operands env) (cond ((primitive-procedure? procedure) (lazapply-primitive procedure (map (lambda (op) (lazeval op env)) operands))) ((compound-procedure? procedure) (lazeval-sequence (procedure-body procedure) (extend-environment (procedure-parameters procedure) (map (lambda (op) (make-thunk op env)) operands) (procedure-environment procedure)))) (else (error "Unknown applicator: " procedure)))) CS 200 Spring 2003
thunky names (define (lazeval expr env) (cond ((self-evaluating? expr) expr) ((variable? expr) (environment-get-value! expr env)) ((lambda? expr) (make-procedure (lambda-parameters expr) (lambda-body expr) env)) ((definition? expr) (define-variable! (definition-variable expr) (lazeval (definition-value expr) env) env)) ((application? expr) (lazapply (lazeval (application-operator expr) env) (application-operands expr) env)) (else (error "Unknown expression: " exp)))) CS 200 Spring 2003
environment-lookup-name (define (environment-lookup-name name env) (if (null? env) (error "No binding " name) (if (frame-contains? name (first-frame env)) (frame-lookup-name name (first-frame env)) (environment-lookup-name name (enclosing-environment env))))) CS 200 Spring 2003
environment-get-value! (define (environment-get-value! name env) (if (null? env) (error "No binding for" name) (if (frame-contains? name (first-frame env)) (let ((np (frame-lookup-name name (first-frame env)))) (if (thunk? (cdr np)) (set-cdr! np (lazeval (thunk-expr (cdr np)) (thunk-env (cdr np))))) (cdr np)) (environment-get-value! name (enclosing-environment env))))) CS 200 Spring 2003
Laziness is Good? > (lazeval '(define true (lambda (x y) x)) the-global-env) ok > (lazeval '(define false (lambda (x y) y)) the-global-env) ok > (lazeval '(define if (lambda (pred tbranch fbranch) (pred tbranch fbranch))) the-global-env) ok > (lazeval '(if true 3 (loop-forever)) the-global-env) 3 Problem Set 7, Question 2: why does this work in LazyScheme, but not in MiniScheme? CS 200 Spring 2003
Charge • Don’t let Lazy Scheme happen to you! • PS7 is long and hard – don’t wait to start it! • Next week • Another Scheme Variation: type checking • Problem classification practice (when the weather is good) • P, NP, Decidable; NP-Complete, Undecidable • Networking CS 200 Spring 2003