Procs w Params EOPL3 Chapter 4 Expressible vs Denotable values Expressible Values the language can express and compute these represented in the languages syntax as expressions Denotable Values ID: 278397
Download Presentation The PPT/PDF document "Assignments and" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
Assignments and Procs w/Params
EOPL3 Chapter 4Slide2
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 declarationsthe 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)
2Slide3
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)
3Slide4
Sharingsharing/aliasing
Point p = new Point();
Point q = p;
call by referencevoid f(Point p){…}; f(q);
CS784(PM)
4Slide5
Side-effects in SchemeUpdate variable: (set!
var
exp)denotes location denotes valueIn Scheme locations are denotable, but not expressible
Sequencing:(begin exp1 exp2 … expn)Ordering of expressions important
CS784(PM)
5Slide6
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)6Slide7
Local Binding: let*
(
let* ([id
val-expr] ...) body ...+)
Similar to let, but evaluates the val-expr
s 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 body
s, and the ids need not be distinct; later bindings shadow earlier bindings.(let* ([x 1] [y (+ x 1)])
(list y x))
(2 1)
CS784(PM)
7Slide8
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 id
s must be distinct.(letrec ((a b) (b 34) (c (+ b 5))) (list a b c)) (#<undefined> 34 39)
(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)
8Slide9
Comparison: let, let*, letrec
(let/let*/
letrec ((v1 e1 ) (v2 e2 ) … (
vn en )) body )letno vi is created until all
ei are evaluated.
none of ei can refer to any vilet*e1 is evaluated; v1 created, bound to e1;e2 is evaluated; v2 created, bound to e2; …;ej can refer to earlier vi,
i < j.letrecvi are created with #undefined as their value.with the above in effect, e1, …, en are evaluated l-to-reach vi is now bound to
ei
CS784(PM)
9Slide10
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)10Slide11
Env and StoreFor 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 storeCS784(PM)
11Slide12
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: dereferencessetref: changes the contentsThis gives a clear account ofallocation, dereferencing, and mutation CS784(PM)
12Slide13
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)
13Slide14
Hidden State
let g =
let counter =
newref(0) in proc (dummy)
begin
setref(counter,-(deref(counter),-1)); deref(counter)
endin let a = (g 11) in let b = (g 11) in -(a,b)
CS784(PM)
14Slide15
environment for gCS784(PM)
15Slide16
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)
16Slide17
conditionalLet (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) = #fCS784(PM)
17Slide18
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)
18Slide19
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)
19Slide20
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)
20Slide21
spec of setref
Given:
(value-of exp1 ρ σ0) = (lc, σ1) (value-of exp2 ρ σ1) = (
val, σ2) ;; note σ1 σ2 orderThen: (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)
21Slide22
Implementationstate σ 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)
22Slide23
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)23Slide24
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)
24Slide25
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)
25Slide26
value-of-program(define value-of-program
(lambda (
pgm) (initialize-store!)
(cases program pgm (a-program (exp1) (value-of exp1 (init-
env))))))
CS784(PM)26Slide27
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)
27Slide28
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 = ExpressionAST: assign-exp (var exp1)Assignment statementVariables are mutable.
CS784(PM)28Slide29
IMPLICIT-REFS examples
let x = 0 in
letreceven(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) endlet g = let count = 0 in proc (dummy) begin set count = --(count,--1);
count endin let a = (g 11) in let b = (g 11)in --(a,b)CS784(PM)
29Slide30
value-of specs(value-of (
var
-exp var) ρ σ) = ( σ(ρ(
var)), σ)environment ρ
binds variables to locationsGiven: (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)
30Slide31
MUTABLE-PAIRSA Language with Mutable Pairs
Reading Assignment
CS784(PM)
31Slide32
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 passingthe denoted value is the same as the expressed value of the actual parameter (EOPL3 page 75).Call-by-valuethe denoted value is a reference to a location containing the expressed value of the actual parameter (EOPL3 section 4.3).
CS784(PM)
32Slide33
call-by-value v. -by-ref
Under call-by-value, a new reference is created for every evaluation of an operand
U
nder call-by-reference, a new reference is created for every evaluation of an operand other than a variable.
CS784(PM)
33Slide34
CALL-BY-REFERENCElet p = proc (x) set x = 4
in 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 = 55
in begin (g z); z endnext
prog: 11 versus --11let swap = proc (x) proc (y) let temp = x in begin set x = y; set y = temp
endin let a = 33 in let b = 44 in begin ((swap a) b); --(a,b) end
CS784(PM)
34Slide35
call-by-referenceExpVal
=
Int + Bool + Proc
DenVal =Ref(ExpVal) a new location is created for every evaluation of an operand other than a variable.
CS784(PM)
35Slide36
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)
36Slide37
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)
37Slide38
variable aliasinglet b = 3 in let p
= proc (x) proc(y)
begin set x = 4;
y endin ((p b) b)
both x and y refer to the same locationYields 4aliasing makes it
difficult to understand programs.CS784(PM)
38Slide39
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)
39Slide40
Lazy Evaluation TermsA
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 thunksThawing: evaluating thunks
CS784(PM)
40Slide41
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)
41Slide42
CALL-BY-NAME
An operand is frozen when it is passed unevaluated to the procedure
Operand is thawed when procedure evaluates itDenVal = Ref(
ExpVal + Thunk)ExpVal =
Int + Bool + Proc
(define-datatype thunk thunk? (a-thunk
(exp1 expression?) (env environment?)))CS784(PM)
42Slide43
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)
43Slide44
call by name designCS784(PM)
44
(
var
-exp (
var) (let ((ref1 (apply-env env var))) (let ((w (deref ref1))) (if (
expval? w) w (value-of-thunk w)))))Slide45
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)
45Slide46
call by needAlternatively, 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)
46Slide47
memoizationCS784(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))))))Slide48
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