assignments and procs w/params eopl3 chapter 4. expressible vs. denotable values expressible values...

48
Assignments and Procs w/Params EOPL3 Chapter 4

Upload: joy-joyce-bayless

Post on 14-Dec-2015

221 views

Category:

Documents


3 download

TRANSCRIPT

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))))) 3628800CS784(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 Redone

let x = newref(0) in letreceven(dummy)=

if zero?(deref(x)) then 1else beginsetref(x, -(deref(x),1));(odd 888)end

odd(dummy)=if zero?(deref(x)) then 0else 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)

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-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

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 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

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)

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 = 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

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)

endCS784(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)

begin

set x = 4;

y

end

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) 11

in (f (infinite-loop 0))• infinite-loop does not

terminate.• above prog returns 11

under lazy evalCS784(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-datatype

thunk 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