Assignment

advertisement
Assignments and Procs w/Params
EOPL3 Chapter 4
Expressible vs. Denotable values
• Expressible Values
– the language can express and
compute these
– represented in the language's
syntax as expressions
• Denotable Values
– represented in syntax by
declarations
– the names and their values
saved within a data structure
(called a namespace or
environment or symbol table
or activation record)
CS784(PM)
• In some languages, these two
are not equal.
• Booleans are expressible in
(early) FORTRAN, but not
denotable.
• Functions are denotable in
many languages, but are not
expressible.
• In (functional subset of)
Scheme, both value spaces are
identical.
• In (full) Scheme, variable
references (pointers) are
denotable but not expressible.
2
Assignment, LHS := RHS
• l-value: left-, location, address, reference, …
• r-value: right-, int, real, address, …
• env and store allow one to describe the
semantics of assignment in a purely functional
style. (DENOTATIONAL SEMANTICS)
• Object language structures are mapped to
similar Scheme structures. (METACIRCULAR INTERPRETER)
CS784(PM)
3
Sharing
• sharing/aliasing
• Point p = new Point();
• Point q = p;
CS784(PM)
• call by reference
• void f(Point p){…};
• f(q);
4
Side-effects in Scheme
• Update variable: (set! var exp)
• denotes location
denotes value
• In Scheme locations are denotable, but not
expressible
• Sequencing:
– (begin exp1 exp2 … expn)
– Ordering of expressions important
CS784(PM)
5
Local Binding: let
• (let proc-id ([id init-expr] ...) body ...+)
• Defines a local procedure. Evaluates
the init-exprs; these become arguments to
the proc. The ids must be distinct.
• (let fac ([n 10])
(if (zero? n)
1
(* n (fac (sub1 n)))))  3628800
CS784(PM)
6
Local Binding: let*
• (let* ([id val-expr] ...) body ...+)
• Similar to let, but evaluates the val-exprs one by
one, creating a location for each id as soon as the
value is available. The ids are bound in the
remaining val-exprs as well as the bodys, and the ids
need not be distinct; later bindings shadow earlier
bindings.
1. (let* ([x 1]
2.
[y (+ x 1)])
3.
(list y x))  (2 1)
CS784(PM)
7
Local Binding: letrec
•
•
(letrec ([id val-expr] ...) body ...+)
Similar to let, but the locations for all ids are created first and filled
with #<undefined>, and all ids are bound in all val-exprs as well as the bodys.
The ids must be distinct.
1.
(letrec ((a b) (b 34) (c (+ b 5)))
2.
(list a b c))  (#<undefined> 34 39)
3.
4.
5.
6.
7.
8.
9.
(letrec ([is-even? (lambda (n)
(or (zero? n)
(is-odd? (sub1 n))))]
[is-odd? (lambda (n)
(and (not (zero? n))
(is-even? (sub1 n))))])
(is-odd? 11))  #t
CS784(PM)
8
Comparison: let, let*, letrec
• (let/let*/letrec ((v1 e1 ) (v2 e2 )
• let
…
(vn en )) body )
• no vi is created until all ei are evaluated.
• none of ei can refer to any vi
• let*
• e1 is evaluated; v1 created, bound to e1;
• e2 is evaluated; v2 created, bound to e2; …;
• ej can refer to earlier vi, i < j.
• letrec
• vi are created with #undefined as their value.
• with the above in effect, e1, …, en are evaluated l-to-r
• each vi is now bound to ei
CS784(PM)
9
Simulating Scheme letrec
(letrec ((v1 exp1) (v2 exp2)) exp)
;; exp1 and exp2 are lambda-forms
(let ((v1 ’*) (v2 ’*))
(set! v1 exp1)
(set! v2 exp2)
exp )
CS784(PM)
10
Env and Store
• For functional subset, it is sufficient to
model env as a function from ids to values.
• For imperative programming that has both
assignment and sharing, separating env
and store is necessary.
– env: identifier  location
– store: location  value
– assignment: location X value X store  store
CS784(PM)
11
EXPLICIT-REFS
• ExpVal = Int + Bool + Proc + Ref(ExpVal)
• DenVal = ExpVal
– Ref(ExpVal) == references to locations that contain
expressed values.
•
•
•
•
newref: allocates a new location, returns a ref to it.
deref: dereferences
setref: changes the contents
This gives a clear account of
– allocation, dereferencing, and mutation
CS784(PM)
12
Even and Odd Redone
let x = newref(0) in letrec
even(dummy)
=
if zero?(deref(x)) then 1
else
begin
setref(x, -(deref(x),1));
(odd 888)
end
odd(dummy)=
if zero?(deref(x)) then 0
else
begin
setref(x, -(deref(x),1));
(even 888)
end
in begin setref(x,13); (odd 888) end
CS784(PM)
13
Hidden State
let g =
let counter = newref(0)
in proc (dummy)
begin
setref(counter,-(deref(counter),-1));
deref(counter)
end
in let a = (g 11)
in let b = (g 11)
in -(a,b)
CS784(PM)
14
environment for g
CS784(PM)
15
Store-Passing Specifications
• [c = v]σ location c is mapped to v in store σ
• (value-of exp1 ρ σ0) = (val1, σ1)
• specification for diff-exp
(value-of exp1 ρ σ0) = (val1, σ1) and
(value-of exp2 ρ σ1) = (val2, σ2)
implies
(value-of (diff-exp exp1 exp2) ρ σ0)
= ( [val1] – [val2], σ2)
(caution: [] incorrect symbols)
CS784(PM)
16
conditional
Let (value-of e1 ρ σ0) = (v1, σ1).
Then
(value-of (if-exp e1 e2 e3) ρ σ0)
= (value-of e2 ρ σ1) if (expval->bool v1) = #t
= (value-of e3 ρ σ1) if (expval->bool v1) = #f
CS784(PM)
17
newref, deref, and setref
Expression ::= newref (Expression)
AST: newref-exp (exp1)
Expression ::= deref (Expression)
AST: deref-exp (exp1)
Expression ::= setref (Expression, Expression)
AST: setref-exp (exp1 exp2)
CS784(PM)
18
Specs of newref
• Given:
– (value-of exp ρ σ0) = (val, σ1), lc !∈ dom(σ1 )
• (value-of (newref-exp exp) ρ σ0)
= ((ref-val lc), [lc=val] σ1)
• newref-exp evaluates its operand. Allocates a
new location lc and stores val in that location.
Then it returns a reference to a location lc that
is new. This means that the new loc is not
already in the domain of σ1.
CS784(PM)
19
Specs of deref
• Given: (value-of exp ρ σ0) = (lc, σ1)
• (value-of (deref-exp exp) ρ σ0) = (σ1(lc),
σ1)
• exp evaluation leaves the store in state σ1.
The value of that argument should be a
reference to a location lc. The deref-exp
then returns the contents of lc in σ1 ,
without any further change to the store.
CS784(PM)
20
spec of setref
• Given:
•
(value-of exp1 ρ σ0) = (lc, σ1)
•
(value-of exp2 ρ σ1) = (val, σ2)
;; note σ1 σ2 order
• Then:
•
(value-of (setref-exp exp1 exp2) ρ σ0)
= ( [23], [lc = val] σ2)
;; caution []
• setref-exp evaluates exp1 first, exp2 second. First value must
be a reference to a location lc.
• setref-exp then updates σ2 by putting val in location lc. It
• could return anything; e.g. 23.
• This expression is executed for its effect, not its value.
CS784(PM)
21
Implementation
• state σ of the store as a Scheme value
– represent the store as a list of expressed
values,
• keep the state in a single global variable
• all the procedures of the impl have access.
• This representation is extremely inefficient.
CS784(PM)
22
A naive model of the store 1/3
(define empty-store
(lambda () ’()))
(define the-store ’uninitialized)
initially
(define get-store
(lambda () the-store))
(define initialize-store!
(lambda ()
(set! the-store (empty-store))))
CS784(PM)
;
23
A naive model of the store 2/3
(define reference?
(lambda (v)
(integer? v)))
(define newref
(lambda (val)
(let ((next-ref (length the-store)))
(set! the-store (append the-store (list val)))
next-ref)))
(define deref
(lambda (ref)
(list-ref the-store ref)))
CS784(PM)
24
A naive model of the store 3/3
(define setref!
(lambda (ref val)
(set! the-store
(letrec
((setref-inner
usage: returns a list like store1, except that position ref1 contains val.
(lambda (store1 ref1)
(cond
((null? store1)
(report-invalid-reference ref the-store))
((zero? ref1)
(cons val (cdr store1)))
(else
(cons
(car store1)
(setref-inner
(cdr store1) (ref1 1))))))))
(setref-inner the-store ref)))))
CS784(PM)
25
value-of-program
(define value-of-program
(lambda (pgm)
(initialize-store!)
(cases program pgm
(a-program (exp1)
(value-of exp1 (init-env))))))
CS784(PM)
26
value-of clauses explicit-ref ops
(newref-exp (exp1)
(let ((v1 (value-of exp1 env)))
(ref-val (newref v1))))
(deref-exp (exp1)
(let ((v1 (value-of exp1 env)))
(let ((ref1 (expval->ref v1)))
(deref ref1))))
(setref-exp (exp1 exp2)
(let ((ref (expval->ref (value-of exp1 env))))
(let ((val2 (value-of exp2 env)))
(begin
(setref! ref val2)
(num-val 23)))))
CS784(PM)
27
IMPLICIT-REFS
• ExpVal = Int + Bool + Proc
– references are no longer expressed values.
• DenVal = Ref(ExpVal)
• Locations are created with each binding operation:
– at each procedure call, let, or letrec.
– This design is called call-by-value, or implicit references.
• Expression ::= set Identifier = Expression
– AST: assign-exp (var exp1)
– Assignment statement
• Variables are mutable.
CS784(PM)
28
IMPLICIT-REFS examples
let x = 0 in letrec
even(dummy) =
if zero?(x) then 1
else begin
set x = --(x,1);
(odd 888)
end
odd(dummy) =
if zero?(x) then 0
else begin
set x = --(x,1);
(even 888)
end
CS784(PM)
let g = let count = 0 in proc
(dummy)
begin
set count = --(count,--1);
count
end
in let a = (g 11)
in let b = (g 11)
in --(a,b)
29
value-of specs
• (value-of (var-exp var) ρ σ) = ( σ(ρ(var)), σ)
– environment ρ binds variables to locations
• Given: (value-of exp1 ρ σ0) = (val1, σ1)
• Then, (value-of (assign-exp var exp1) ρ σ0)
= ( [27], [ρ(var) = val1] σ1)
;; caution: []
• For procedure call, the rule becomes
(apply-procedure (procedure var body ρ) val σ)
= (value-of body [var = lc]ρ [lc = val]σ )
CS784(PM)
30
MUTABLE-PAIRS
• A Language with Mutable Pairs
• Reading Assignment
CS784(PM)
31
Parameter-Passing Variations
• When a procedure body is executed,
– its formal parameter is bound to a denoted value.
– It must be passed from the actual argument in the call.
• Natural parameter passing
– the denoted value is the same as the expressed value of
the actual parameter (EOPL3 page 75).
• Call-by-value
– the denoted value is a reference to a location containing
the expressed value of the actual parameter (EOPL3
section 4.3).
CS784(PM)
32
call-by-value v. -by-ref
• Under call-by-value, a new reference is
created for every evaluation of an operand
• Under call-by-reference, a new reference is
created for every evaluation of an operand
other than a variable.
CS784(PM)
33
CALL-BY-REFERENCE
let p = proc (x) set x = 4
in let a = 3
in begin (p a); a end
let f = proc (x) set x = 44
in let g = proc (y) (f y)
in let z = 55
in begin (g z); z end
• next prog: 11 versus --11
CS784(PM)
let swap = proc (x) proc (y)
let temp = x
in begin
set x = y;
set y = temp
end
in let a = 33
in let b = 44
in begin
((swap a) b);
--(a,b)
end
34
call-by-reference
• ExpVal = Int + Bool + Proc
• DenVal =Ref(ExpVal)
• a new location is created for every
evaluation of an operand other than a
variable.
CS784(PM)
35
call-by-ref implementation
(define apply-procedure
(lambda (proc1 val)
(cases proc proc1
(procedure
(var body savedenv)
(value-of body
(extend-env var
val saved-env))))))
CS784(PM)
(call-exp (rator rand)
(let ((proc
(expval->proc
(value-of
rator env)))
(arg (value-ofoperand rand env)))
(apply-procedure proc
arg)))
36
value-of-operand
(define value-of-operand
(lambda (exp env)
(cases expression exp
(var-exp (var) (apply-env env var))
(else
(newref (value-of exp
env))))))
CS784(PM)
37
variable aliasing
let b = 3 in let p
= proc (x) proc(y)
begin
set x = 4;
y
end
in ((p b) b)
CS784(PM)
• both x and y refer to
the same location
• Yields 4
• aliasing makes it
difficult to understand
programs.
38
Lazy Evaluation
• Under lazy evaluation,
an operand in a
procedure call is not
evaluated until it is
needed by the procedure
body.
• Sometimes in a given
call a procedure never
evaluates some of its
formal parameters.
• This can potentially
avoid non-termination.
CS784(PM)
letrec infinite-loop (x) =
infinite-loop(--(x, --1))
in let f = proc (z) 11
in (f (infinite-loop 0))
• infinite-loop does not
terminate.
• above prog returns 11
under lazy eval
39
Lazy Evaluation Terms
• A thunk is a procedure with no arguments.
• One can delay (perhaps indefinitely) the
evaluation of an operand by encapsulating it
as a thunk.
• Freezing: forming thunks
• Thawing: evaluating thunks
CS784(PM)
40
call-by-name, -by-need
• call-by-name: invoke the thunk every time
the parameter is referred to.
– In the absence of side effects this is a waste of
time, since the same value is returned each
time.
• call-by-need: record the value of each thunk
the first time it is invoked, and thereafter
refers to the saved value.
– an example of memoization.
CS784(PM)
41
CALL-BY-NAME
• An operand is frozen
when it is passed
unevaluated to the
procedure
• Operand is thawed when
procedure evaluates it
• DenVal = Ref(ExpVal +
Thunk)
• ExpVal = Int + Bool +
Proc
CS784(PM)
(define-datatype
thunk thunk?
(a-thunk
(exp1 expression?)
(env
environment?)))
42
value-of-operand
(define value-of-operand
(lambda (exp env)
(cases expression exp
(var-exp (var) (apply-env env var))
(else
(newref (a-thunk exp env))))))
CS784(PM)
43
call by name design
(var-exp (var)
(let ((ref1 (apply-env env var)))
(let ((w (deref ref1)))
(if (expval? w)
w
(value-of-thunk w)))))
CS784(PM)
44
value-of-thunk: Thunk→ExpVal
(define value-of-thunk
(lambda (th)
(cases thunk th
(a-thunk (exp1 saved-env)
(value-of exp1 saved-env))))
CS784(PM)
45
call by need
• Alternatively, once we find the value of the
thunk, we can install that expressed value
in the same location, so that the thunk will
not be evaluated again.
• This is an instance of a general strategy
called memoization.
CS784(PM)
46
memoization
(var-exp (var)
(let ((ref1 (apply-env env var)))
(let ((w (deref ref1)))
(if (expval? w)
w
(let ((val1 (value-of-thunk w)))
(begin
(setref! ref1 val1)
val1))))))
CS784(PM)
47
Lazy Evaluation Summary
• In the absence of (side) effects,
it supports reasoning about
programs in a particularly
simple way.
• The effect of a procedure call
can be modeled by replacing
the call with the body of the
procedure, with every reference
to a formal parameter in the
body replaced by the
corresponding operand.
• This evaluation strategy is the
basis for the lambda calculus,
where it is called β-reduction.
CS784(PM)
• Unfortunately, call-by-name
and call-by-need make it
difficult to determine the
order of evaluation, which in
turn is essential to
understanding a program
with effects.
• Thus lazy evaluation is
popular in functional
programming languages
(those with no effects), and
rarely found elsewhere.
48
Download