Assignments and Procs w/Params EOPL3 Chapter 4
Feb 25, 2016
Assignments and Procs w/Params
EOPL3 Chapter 4
2
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)
• 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.
CS784(PM)
3
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. (META-CIRCULAR INTERPRETER)
CS784(PM)
4
Sharing
• sharing/aliasing• Point p = new Point();
• Point q = p;
• call by reference• void f(Point p){…};
• f(q);
CS784(PM)
5
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)
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. (letrec ([is-even? (lambda (n)4. (or (zero? n)5. (is-odd? (sub1 n))))]6. [is-odd? (lambda (n)7. (and (not (zero? n))8. (is-even? (sub1 n))))])9. (is-odd? 11)) #t
CS784(PM) 8
Comparison: let, let*, letrec• (let/let*/letrec ((v1 e1 ) (v2 e2 ) … (vn en )) body )• let
• 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
10
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)
11
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)
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 Redonelet x = newref(0) in letrec
even(dummy)=if zero?(deref(x)) then 1else beginsetref(x, -(deref(x),1));(odd 888)endodd(dummy)=if zero?(deref(x)) then 0else beginsetref(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)beginsetref(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
21
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)
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-innerusage: 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
28
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)
IMPLICIT-REFS exampleslet x = 0 in letreceven(dummy) =
if zero?(x) then 1 else beginset x = --(x,1);(odd 888)end
odd(dummy) = if zero?(x) then 0else beginset x = --(x,1);(even 888)end
let g = let count = 0 in proc (dummy)beginset count = --(count,--1);countend
in let a = (g 11)in let b = (g 11)
in --(a,b)
CS784(PM) 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 = 4in let a = 3
in begin (p a); a end
let f = proc (x) set x = 44in let g = proc (y) (f y)
in let z = 55in begin (g z); z end
• next prog: 11 versus --11
let swap = proc (x) proc (y)let temp = xin beginset x = y;set y = tempend
in let a = 33in let b = 44in begin((swap a) b);--(a,b)end
CS784(PM) 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 saved-env)(value-of body(extend-env var val saved-env))))))
(call-exp (rator rand) (let ((proc
(expval->proc (value-of
rator env)))(arg (value-of-
operand rand env)))(apply-procedure proc arg)))
CS784(PM) 36
37
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)
variable aliasing
let b = 3 in let p= proc (x) proc(y)
beginset x = 4;yend
in ((p b) b)
• both x and y refer to the same location
• Yields 4• aliasing makes it
difficult to understand programs.
CS784(PM) 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.
letrec infinite-loop (x) = infinite-loop(--(x, --1))
in let f = proc (z) 11in (f (infinite-loop 0))
• infinite-loop does not terminate.
• above prog returns 11 under lazy eval
CS784(PM) 39
40
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)
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
(define-datatypethunk thunk?(a-thunk
(exp1 expression?)
(env environment?)))
CS784(PM) 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
CS784(PM) 44
(var-exp (var)(let ((ref1 (apply-env env var)))
(let ((w (deref ref1)))(if (expval? w)
w(value-of-thunk w)))))
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
CS784(PM) 47
(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))))))
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.
• 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.
CS784(PM) 48