1 / 48

Assignments and Procs w/ Params

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

lupita
Télécharger la présentation

Assignments and Procs w/ Params

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  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)

  4. Sharing • sharing/aliasing • Point p = new Point(); • Point q = p; • call by reference • void f(Point p){…}; • f(q);

  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

  6. Local Binding: let • (letproc-id ([idinit-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

  7. Local Binding: let* • (let* ([idval-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 remainingval-exprs as well as the bodys, and the ids need not be distinct; later bindings shadow earlier bindings. • (let* ([x 1] • [y (+ x 1)]) • (list y x))  (2 1)

  8. Local Binding: letrec • (letrec ([idval-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. • (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

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

  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 )

  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

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

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

  14. 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)

  15. environment for g

  16. 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)

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

  18. 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)

  19. Specs of newref • Given: • (value-of exp ρ σ0) = (val, σ1),lc !∈ dom(σ1 ) • (value-of (newref-exp exp) ρ σ0)= ((ref-vallc), [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.

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

  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.

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

  23. 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))))

  24. 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)))

  25. 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)))))

  26. value-of-program (define value-of-program (lambda (pgm) (initialize-store!) (cases program pgm (a-program (exp1) (value-of exp1 (init-env))))))

  27. 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)))))

  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.

  29. 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)

  30. 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]σ )

  31. MUTABLE-PAIRS • A Language with Mutable Pairs • Reading Assignment

  32. 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).

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

  34. 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) end

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

  36. call-by-ref implementation (define apply-procedure (lambda (proc1 val) (cases proc proc1 (procedure (var body saved-env) (value-of body (extend-envvarval saved-env)))))) (call-exp (rator rand) (let ((proc (expval->proc (value-of ratorenv))) (arg (value-of-operand rand env))) (apply-procedure proc arg)))

  37. value-of-operand (define value-of-operand (lambda (exp env) (cases expression exp (var-exp (var) (apply-envenvvar)) (else (newref (value-of exp env))))))

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

  39. 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 eval

  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

  41. 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, andthereafter refers to the saved value. • an example of memoization.

  42. 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 thunkthunk? (a-thunk (exp1 expression?) (env environment?)))

  43. value-of-operand (define value-of-operand (lambda (exp env) (cases expression exp (var-exp (var) (apply-envenvvar)) (else (newref (a-thunk exp env))))))

  44. call by name design (var-exp (var) (let ((ref1 (apply-envenvvar))) (let ((w (deref ref1))) (if (expval? w) w (value-of-thunk w)))))

  45. value-of-thunk: Thunk→ExpVal (define value-of-thunk (lambda (th) (cases thunkth (a-thunk (exp1 saved-env) (value-of exp1 saved-env))))

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

  47. memoization (var-exp (var) (let ((ref1 (apply-envenvvar))) (let ((w (deref ref1))) (if (expval? w) w (let ((val1 (value-of-thunk w))) (begin (setref! ref1 val1) val1))))))

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

More Related