Lecture 5: Lazy Scheme (Thunking about Thunks) CS655: Programming Languages David Evans University of Virginia http://www.cs.virginia.edu/~evans Computer Science.

Download Report

Transcript Lecture 5: Lazy Scheme (Thunking about Thunks) CS655: Programming Languages David Evans University of Virginia http://www.cs.virginia.edu/~evans Computer Science.

Lecture 5: Lazy Scheme
(Thunking about Thunks)
CS655: Programming Languages
David Evans
University of Virginia
http://www.cs.virginia.edu/~evans
Computer Science
Menu
• Finish Mini-Scheme Interpreter
• Changing Language Semantics
1 Feb 2001
CS 655: Lecture 5
2
Last Time: Mini-Scheme
(define (apply proc operand env)
(bind-variable (car (car (cdr proc))) operand
(extend-environment env)))))
(define (eval expr env)
(if (number? expr) expr
(if (symbol? expr)
(lookup-variable-value expr env)
(if (and (list? expr) (eq? (car expr) 'lambda))
(list 'procedure (car (cdr expr)) (car (cdr (cdr expr))))
(apply (eval (car expr) env)
(eval (car (cdr expr)) env) env)))))
1 Feb 2001
CS 655: Lecture 5
3
Handling Primitives
;; represented by (primitive func)
(define (apply proc operand env)
(if (eq? (car proc) 'primitive)
((car (cdr proc)) operand)
same as before]
1 Feb 2001
CS 655: Lecture 5
4
Handling Primitives: Eval
(define (eval expr env)
(if (or (number? expr)
(and (list? expr)
(eq? (car expr) 'primitive))
expr
rest is same]
1 Feb 2001
CS 655: Lecture 5
5
Primitives: Environment
(define global-env
(bind-variable 'minus (list 'primitive -)
(bind-variable 'inc
(list 'primitive (lambda (x) (+ x 1)))
'(()))))
1 Feb 2001
CS 655: Lecture 5
6
Mini-Scheme Examples
(eval ‘(minus 3) global-env)
-3
(eval '((lambda (x) (inc x)) 3) global-env)
4
1 Feb 2001
CS 655: Lecture 5
7
An Entire Mini-Scheme Interpreter!
(define (apply proc operand env)
(if (eq? (car proc) 'primitive) ((car (cdr proc)) operand)
(eval (car (cdr (cdr proc)))
(bind-variable (car (car (cdr proc))) operand
(extend-environment env)))))
(define (eval expr env)
(if (or (number? expr)
(and (list? expr) (eq? (car expr) 'primitive))) expr
(if (symbol? expr)
(lookup-variable-value expr env)
(if (and (list? expr) (eq? (car expr) 'lambda))
(list 'procedure (car (cdr expr)) (car (cdr (cdr expr))))
(apply (eval (car expr) env) (eval (car (cdr expr)) env) env)))))
1 Feb 2001
CS 655: Lecture 5
8
All Programs are Really
Language Implementations
Recall our definition of a language (Lecture 1):
A description of pairs (S, M), where S
stands for sound, or any kind of surface
forms, and M stands for meaning. A
theory of language must specify the
properties of S and M, and how they are
related.
1 Feb 2001
CS 655: Lecture 5
9
What is a Language
Implementation?
A description of pairs (S, M), where S
stands for sound, or any kind of surface
forms, and M stands for meaning. A
theory of language must specify the
properties of S and M, and how they are
related. An implementation of a
language is a function from S to M.
1 Feb 2001
CS 655: Lecture 5
10
Examples of Language
Implementations
• Our Mini-Scheme Interpreter (eval)
S: <expression, environment>
M: value = number | procedure
eval: S  M
1 Feb 2001
CS 655: Lecture 5
11
Language Implementations
• Mystery Language Implementation
S: HTML x user input
M: pixels on screen x user input  HTTP
Web Browser: S  M
• Mystery Language Implementation:
S: user input x network input
M: pixels on screen x network output
Doom: S  M
1 Feb 2001
CS 655: Lecture 5
12
Language Implementations
• My Gyromouse
S: physical gestures in space x mouse clicks
M: Windows events
Gyromouse and software: S  M
1 Feb 2001
CS 655: Lecture 5
13
Changing Languages
• Change S
– Allow new surface forms - new surface forms map
to the old surface forms, and then to the old
meanings
– Gyromouse (without its software) is just a new
surface form for the regular mouse
• Change M
– Change the meaning of surface forms
– Gyromouse recognizes special gestures, and
assigns them meanings not available using
regular mouse
1 Feb 2001
CS 655: Lecture 5
14
Scheme Evaluation
1. To evaluate a compound expression,
evaluate the subexpressions, then
apply the value of the first
subexpression to the values of the
other subexpressions.
2. To apply a procedure to a list of
arguments, evaluate the procedure in
a new environment that binds the
formal parameters of the procedure to
the arguments it is applied to.
1 Feb 2001
CS 655: Lecture 5
15
Evaluation Order
• Applicative Order (Eager) Evaluation
– Procedure operands are evaluated when
the procedure is applied
• “To evaluate a compound expression, evaluate
the subexpressions ...”
• Normal Order (Lazy) Evaluation
– Evaluate and expression only when you
really need its value
1 Feb 2001
CS 655: Lecture 5
16
Laziness can save work
• Eager Evaluation (Applicative)
– Read all assignments as soon as they are
assigned
• Lazy Evaluation (Normal)
– Read something only when you absolutely need
it to do the problem set
• Lazy Evaluation requires less total work
since some reading assignments may not be
necessary to do problem set (but is not
recommended for students in this class)
1 Feb 2001
CS 655: Lecture 5
17
Laziness Can Be Useful
(define (p x) (p x))
(define (f x) 3)
(f (p 6))
Eager: no value (does infinite work)
Lazy:
3
never needs to evaluate (p 6)
1 Feb 2001
CS 655: Lecture 5
18
Lazy Scheme Evaluation
1. To evaluate a compound expression,
evaluate the first subexpression, then
apply the value of the first subexpression
to the other subexpressions.
2. To apply a procedure to a list of
arguments, evaluate the procedure in a
new environment that binds the formal
parameters of the procedure to the
arguments it is applied to. Evaluate an
argument when its value is really needed.
1 Feb 2001
CS 655: Lecture 5
19
Really Needed?
• The value of an expression is really
needed when:
– It is passed to a primitive procedure
Primitive procedures are “strict”.
– It needs to be printed for human
• Until then, we just need something (called
a thunk) we can evaluate when necessary
to produce the value we would have
gotten if we evaluated it at first application
1 Feb 2001
CS 655: Lecture 5
20
Lazy Eval
(define (eval expr env)
(if (or (number? expr)
(define (make-thunk exp env)
(list 'thunk exp env))
(and (list? expr) (eq? (car expr) 'primitive)))
expr
(if (symbol? expr)
(lookup-variable-value expr env)
(if (and (list? expr) (eq? (car expr) 'lambda))
(list 'procedure (car (cdr expr)) (car (cdr (cdr expr))))
(apply (eval (car expr) env)
(make-thunk (car (cdr expr)) env)
env)))))
was eval before
1 Feb 2001
CS 655: Lecture 5
21
Unthunking
(define (apply proc operand env)
(if (eq? (car proc) 'primitive)
(force-eval operand env))
((car (cdr proc)) operand
(eval (car (cdr (cdr proc)))
(bind-variable (car (car (cdr proc)))
operand
(extend-environment env)))))
1 Feb 2001
CS 655: Lecture 5
22
Unthunking
(define (force-eval expr env)
(if (or (number? expr) (has-tag expr 'primitive)) expr
(if (has-tag expr 'thunk)
(force-eval (cadr expr) (caddr expr))
(if (symbol? expr)
(force-eval (lookup-variable-value expr env) env)
(if (has-tag expr 'lambda)
(list 'procedure (car (cdr expr)) (car (cdr (cdr expr))))
(force-eval
(apply (force-eval (car expr) env)
(make-thunk (car (cdr expr)) env) env)))))))
1 Feb 2001
CS 655: Lecture 5
23
Some Handy Definitions
• The world’s most commonly-written
function
(define (nt x) (nt x))
nt – the non-terminating function
• Global environment
(define global-env
(bind-variable 'minus (list 'primitive -)
(bind-variable 'nt (list 'primitive nt)
'(())))))
1 Feb 2001
CS 655: Lecture 5
24
Lazy Evaluations
(eval 3 global-env)
3
(eval '((lambda (x) x) 3) global-env)
(thunk 3
(((minus primitive #[arity-dispatched-procedure 3])
(nt primitive #[compound-procedure 65 nt]))))
1 Feb 2001
CS 655: Lecture 5
25
Forcing Evaluation
• The value of an expression is really
needed when:
It is passed to a primitive procedure
Primitive procedures are “strict”.
– It needs to be printed for human
(define (geval expr)
(force-eval (eval expr global-env)
global-env))
1 Feb 2001
CS 655: Lecture 5
26
Less Lazy Evaluations
(geval '((lambda (x) x) 3))
3
(geval '((lambda (x) 3) (nt 7)))
3
(geval '((lambda (x) x) (nt 7)))
no value
1 Feb 2001
CS 655: Lecture 5
27
Debugging in Scheme
(trace <procedure>)
(trace eval)
(trace apply)
(trace force-eval)
(trace make-thunk)
1 Feb 2001
CS 655: Lecture 5
28
Trace Run
(geval '((lambda (x) 3) (nt 7)))
[Entering #[compound-procedure 60 eval]
Args: ((lambda (x) 3) (nt 7))
(((minus primitive ...)]
[Entering #[compound-procedure 61 make-thunk]
Args: (nt 7) (((minus primitive ...)]
[(thunk (nt 7) (((minus primitive #[arity-dispatchedprocedure 3]) (nt prim...
<== #[compound-procedure 61 make-thunk]
Args: (nt 7) ...]
1 Feb 2001
CS 655: Lecture 5
29
Edited Trace: (geval '((lambda (x) 3) (nt 7)))
[Entering eval] Args: ((lambda (x) 3) (nt 7)) env
[Entering make-thunk] Args: (nt 7) env
[returns (thunk (nt 7) env)]
[Entering force-eval] Args: (lambda (x) 3) env
[returns (procedure (x) 3)]
[Entering apply] Args: (procedure (x) 3) (thunk (nt 7) env)
[Entering eval] Args: 3 ((x thunk (nt 7)) global-env)
[eval returns 3]
[apply returns 3]
[eval returns 3]
[Entering force-eval] Args: 3 global-env
[force-eval returns 3]
;Value: 3
1 Feb 2001
CS 655: Lecture 5
30
Challenge #2
• SICP does lazy evaluation in a
somewhat different way. Is the way I
did it equivalent for the functional subset
of scheme?
– Prove (“show convincingly”) or disprove
(show a counterexample)
– Note: if there are silly bugs in my
implementation, it doesn’t count.
1 Feb 2001
CS 655: Lecture 5
31
Charge
• Source code from today is on web site
• PS2 (out Tuesday): Changing MiniScheme
– Before Sunday: email me feedback on
problem set mechanics (work in pairs, choice
of partners, etc.)
• Next time: An even simpler language
1 Feb 2001
CS 655: Lecture 5
32