Presentation is loading. Please wait.

Presentation is loading. Please wait.

Imperative Programming: Mutable data (local state, letrec, set!) Example 1: counter (define counter (let ((count 0)) (lambda () (set! count (+ count 1))

Similar presentations


Presentation on theme: "Imperative Programming: Mutable data (local state, letrec, set!) Example 1: counter (define counter (let ((count 0)) (lambda () (set! count (+ count 1))"— Presentation transcript:

1 Imperative Programming: Mutable data (local state, letrec, set!) Example 1: counter (define counter (let ((count 0)) (lambda () (set! count (+ count 1)) count))) (define counter (let ((count 0)) (lambda () (set! count (+ count 1)) count))) How would this work in the substitution model? app-eval [ ((lambda (count) (lambda () (begin (set! count (+ count 1)) count)) 0 )] app-eval [ (lambda () (begin (set! 0 (+ 0 1)) 0)) ] app-eval [ (begin (set! 0 (+ 0 1)) 0) ] ==> 0 The substitution model cannot account for change! change requires objects that keep local states. The substitution step has to be strengthened to enable binding of variables (parameters) to actual argument values. 1

2 Imperative Programming: Mutable data (local state, letrec, set!) GE counter (lambda () (set!... E1 count=0 P = B= (set!... count P = count B= (lambda () (set!... count (set!... count E2 1 > (counter) 2 Note that count is the local state of the counter object. Conclusion: In functional languages, objects are implemented as runtime generated closures. > (counter) ;;; How would the box diagram look like? 1 Example 1: counter (define counter (let ((count 0)) (lambda () (set! count (+ count 1)) count))) (define counter (let ((count 0)) (lambda () (set! count (+ count 1)) count))) 2

3 Imperative Programming: Mutable data (local state, letrec, set!) Example 2: A chess player object: (define make-player (lambda (total) (letrec ((steps 0) (get-steps (lambda () steps)) (set-steps (lambda () (set! steps (+ steps 1)))) (get-total (lambda () total)) (set-total (lambda (piece) (let ((piece-value (cond ( (eq? piece 'queen) 9) ((eq? piece 'rook) 5) ((eq? piece 'bishop) 3) ((eq? piece 'knight) 3) ((eq? piece 'pawn) 1) (else 0)))) (set! total (- total piece-value))))) (dispatch (lambda (m) (cond ((eq? m 'set-total) set-total) ((eq? m 'set-steps) set-steps) ((eq? m 'get-total) get-total) ((eq? m 'get-steps) get-steps) (else (error "Unknown request"))))) ) dispatch))) (define make-player (lambda (total) (letrec ((steps 0) (get-steps (lambda () steps)) (set-steps (lambda () (set! steps (+ steps 1)))) (get-total (lambda () total)) (set-total (lambda (piece) (let ((piece-value (cond ( (eq? piece 'queen) 9) ((eq? piece 'rook) 5) ((eq? piece 'bishop) 3) ((eq? piece 'knight) 3) ((eq? piece 'pawn) 1) (else 0)))) (set! total (- total piece-value))))) (dispatch (lambda (m) (cond ((eq? m 'set-total) set-total) ((eq? m 'set-steps) set-steps) ((eq? m 'get-total) get-total) ((eq? m 'get-steps) get-steps) (else (error "Unknown request"))))) ) dispatch))) We’ll examine a simpler representation of a chess player by using only the procedure set-total. A chase player object is represent by a dispatch procedure. Based on a given message it invokes internal procedures of the object. total and steps which keep track of the player’s points and the number of steps respectively, are the object’s local state variables. 3

4 Imperative Programming: Mutable data (local state, letrec, set!) Example 2: A chess player object: (define make-player (lambda (total) (lambda (piece) (let ((piece-value (cond ((eq? piece 'queen) 9) ((eq? piece 'rook) 5) ((eq? piece 'bishop) 3) ((eq? piece 'knight) 3) ((eq? piece 'pawn) 1) (else 0)))) (set! total (- total piece-value)) total)))) (define make-player (lambda (total) (lambda (piece) (let ((piece-value (cond ((eq? piece 'queen) 9) ((eq? piece 'rook) 5) ((eq? piece 'bishop) 3) ((eq? piece 'knight) 3) ((eq? piece 'pawn) 1) (else 0)))) (set! total (- total piece-value)) total)))) We represent a chess player by a procedure that keeps track of his total points: Initially, a player has a certain total number of points and he loses points according to pieces he loses in the game. Local state (initialized) ((make-player 39) ‘queen) E1 total = 39 (lambda (piece)… P=(piece) B=(let ((piece-value… E2 Piece = ‘queen (let ((piece-value… P=(piece-value) B=(set!... total… P=(total) B=(lambda (piece)… make-player GE E3 piece-value = 9 (set! total (- total piece-value)) total… 30 4

5 Imperative Programming: Mutable data (local state, letrec, set!) Example 3: letrec The letrec expression can be used to define local recursive procedures. The evaluation rule for this expression is not supported by the functional programming model (e.g, applicative-eval) without rewriting the code of the recursive procedure. However, it can be supported by the imperative programming with the environment model. (letrec ((f1 lambda-exp1)... (fn lambda-expn)) e1...em) (let ((f1 ’unassigned)... (fn ’unassigned)) (set! f1 lambda-exp1)... (set! fn lambda-expn) e1...em) To support the evaluation of a letrec expression, it is handled as a derived expression: 5

6 Imperative Programming: Mutable data (local state, letrec, set!) Example 3: letrec env-eval[ ( letrec ( (fact ( lambda (n) (if (= n 0) 1 (* n (fact (- n 1)))) )) (fact 3) ),GE]==> Assume letrec was translated to let which was translated to an application… env-eval[ (( lambda (fact) (set! fact (lambda (n) (if (= n 0) 1 (* n (fact (- n 1))))) (fact 3) ) 'uassigned ), GE] ==> env-eval[ (set! fact (lambda (n) (if (= n 0) 1 (* n (fact (- n 1))))), E1] GE Params: fact Body: (set!... (fact 3) (A) fact='unassigned E1 (set.. (fact 3) Remains to evaluate… (next slide) Params: n Body: (if… ) (B) 6

7 Imperative Programming: Mutable data (local state, letrec, set!) Example 3: letrec ==> env-eval[ (fact 3), E1 ] env-eval[ fact, E1 ] ==> lookup-varibale-value (fact,E1) = (B) env-eval[ 3, E1 ] ==> 3 Let E2 be the extended environment… env-eval[(* n (fact (- n 1))), E2] ==> env-eval[*,E2] ==> ==> env-eval [n,E2]==> 3 (lookup) ==> env-eval[(fact (- n 1)), E2] ==> env-eval[fact, E2] ==> lookup-variable-value(fact,E2): (B) … n = 3 E2 …(* n (fact (- n 1)))… 7 GE Params: fact Body: (set!... (fact 3) (A) fact='unassigned E1 (set.. (fact 3) Params: n Body: (if… ) (B)

8 Imperative Programming: Mutable data (local state, letrec, set!) Example 3: letrec Compare the last diagram with the diagram resulting from using let instead of letrec: Env-eval[ (letrec ((fact (lambda (n) (if (= n 0) 1 (* n (fact (- n 1)))))) (fact 3)),GE]==> fact E1 GE Params: fact Body: (set.. (fact 3) (A) (set.. (fact 3) Params: n Body: (if… ) (B) (a)The set statement is removed for A’s body (according to the way a let expression is derived) (b)Procedure B “points” to the GE! B is not defined within a closure (as earlier), but as an argument evaluated in the GE. (c)When evaluating B’s body, fact is unbound! 8 Env-eval[ ( (lambda (fact) (fact 3)) (lambda (n) (if (= n 0) 1 (* n (fact (- n 1))))) ), GE]

9 Imperative Programming: Mutable lists Example 4: The built-in LIST ADT includes the mutators set-car! and set-cdr! : ; Type: Pair(T1,T2) * T -> void ; Purpose: modify the car pointer of 'pair' to point to 'value' ; Signature: set-car!(pair, value) ; Signature: set-cdr!(pair, value) > (define x (list (list 'a 'b) 'c 'd) ) > x ((a b) c d) a b c d > (define y (list 'e 'f)) e f > (set-car! x y) Notice the difference from the following: > (define z (cons y (cdr x)) ) > z ((e f) c d) > x ((e f) c d) 9 > x ((e f) c d)

10 Imperative Programming: Mutable lists Example 4: The built-in LIST ADT includes the mutators set-car! and set-cdr! : ; Type: Pair(T1,T2) * T -> void ; Purpose: modify the car pointer of 'pair' to point to 'value' ; Signature: set-car!(pair, value) ; Signature: set-cdr!(pair, value) > (equal? x z) Well, what do you think? c d e f #t > (eq? x z) #f Why? equal? is the overloaded procedure that checks equality recursively. eq? is an overloaded procedure that checks if the compared arguments are the same data (object). 10

11 Imperative Programming: Mutable lists Example 5: modify list In the following example we see how an element in a list data structure points to the list itself: > (define x (list 1 2 3)) > (set-cdr! x x) > x #0=(1. #0#) The printed representation of the pointer. ; 1. Signature: modify-list!(lst, from, to) ; 2. Type: List(T)*T*T -> Void ; 3. Purpose: Modify the cdr of 'from' to point to the part of the list starting with 'to', if 'from' and 'to' are members of the list. (define (modify-list! lst from to) (let ( (f (memq from lst)) (t (memq to lst)) ) (if (and f t) (set-cdr! f t)))) ; 1. Signature: modify-list!(lst, from, to) ; 2. Type: List(T)*T*T -> Void ; 3. Purpose: Modify the cdr of 'from' to point to the part of the list starting with 'to', if 'from' and 'to' are members of the list. (define (modify-list! lst from to) (let ( (f (memq from lst)) (t (memq to lst)) ) (if (and f t) (set-cdr! f t)))) We use a similar idea in the following procedure If from > to, the result is a circular list: > (modify-list! (list ) 4 2) 1  2  3  4  2  3  4  … If from < to, then list elements are “skipped”: >(modify-list! (list ) 2 4) 1  2  4 (non-circular) 11

12 12 Question1: Can a while expression be supported in a functional programming evaluator? NO! in functional programming there is no change of state. Particularly, the result of evaluating the condition clause of a while loop will always remain the same. An ability to change state is required! > (define x 0) > (define n 4) > (while (> n 0) (begin (set! x (+ x n)) (set! n (- n 1))) ) > x 10 In the (Meta-Circular Environment Based) interpreter for imperative programming, support for set! expressions is added. This gives motivation for supporting while expressions: Imperative Programming Evaluator: Adding while expressions

13 13 Question2: Can while be defined as a user procedure (in the imperative model)? (define while (lambda (pred body) (if pred (begin (body) (while pred body)))) > (define x 2) > (while (> x 0) (lambda () (begin (set! x (+ x n)) (display x))) ) So the answer is?...Yes! BUT, only in the normal evaluation approach. (define while (lambda (pred body) (if pred (begin (body) (while pred body)))) According to the normal evaluation approach, the predicate must be evaluated. The expression constituting pred is pass to recursive calls, as opposed to the value of the pred expression in the eager approach > (while (> x 0) (lambda () (begin (set! x (+ x n)) (display x)))) 1 Endless loop… After the first time pred is evaluated to #t, It remains #t in every recursive call. Imperative Programming Evaluator: Adding while expressions

14 (define while? (lambda (exp) (tagged-list? exp 'while))) To support while expressions, we add the appropriate parser procedures: (define while-pred (lambda (exp) (car (get-content exp)))) (define while-pred (lambda (exp) (car (get-content exp)))) (define while-body (lambda (exp) (cadr (get-content exp)))) (define while-body (lambda (exp) (cadr (get-content exp)))) Imperative Programming Evaluator: Adding while expressions 14

15 (define derived? (lambda (exp) (or … (while? exp)))) (define shallow-derive (lambda (exp) (cond … ((while? exp) (while->iteration-expression exp))))) (define shallow-derive (lambda (exp) (cond … ((while? exp) (while->iteration-expression exp))))) 1. Add to derived? 2. Add to shallow-derive (option A) (option A) Adding while as a derived expression Imperative Programming Evaluator: Adding while expressions 3. Add the translation procedure: while->iteration-expression… (while (> n 0) (begin (set! x (+ x n)) (set! n (- n 1)))) (while (> n 0) (begin (set! x (+ x n)) (set! n (- n 1)))) (letrec ((iter (lambda () (if (> n 0) (begin (begin (set! x (+ x n)) (set! n (- n 1))) (iter)) ‘done)))) (iter)) (letrec ((iter (lambda () (if (> n 0) (begin (begin (set! x (+ x n)) (set! n (- n 1))) (iter)) ‘done)))) (iter)) Any problem with the solution above?There might be if iter is a predefined procedure! (while (> (iter n) 0) (set! n (- n (iter n)))) (while (> (iter n) 0) (set! n (- n (iter n)))) (letrec ((iter (lambda () (if (> (iter n) 0) (begin (set! n (- n (iter n)))) (iter)) ‘done)))) (iter)) (letrec ((iter (lambda () (if (> (iter n) 0) (begin (set! n (- n (iter n)))) (iter)) ‘done)))) (iter)) 15

16 Imperative Programming Evaluator: Adding while expressions 3. Add the translation procedure: while->iteration-expression… Second try: (while (> (iter n) 0) (set! n (- n (iter n)))) (while (> (iter n) 0) (set! n (- n (iter n)))) (let ( (action (lambda () (set! n (- n (iter n))))) (condition (lambda () (> (iter n) 0))) ) (letrec ((iter (lambda () ( if (condition) (begin (action) (iter)) 'ok)))) (iter))) (let ( (action (lambda () (set! n (- n (iter n))))) (condition (lambda () (> (iter n) 0))) ) (letrec ((iter (lambda () ( if (condition) (begin (action) (iter)) 'ok)))) (iter))) 16 (option A) (option A) Adding while as a derived expression

17 Imperative Programming Evaluator: Adding while expressions The translation procedure: (define while->iteration-expression (lambda (exp) (let ((condition (make-lambda (list) (list (while-pred exp)))) (action (make-lambda (list) (list (while-body exp))))) derive (derive (make-let (list (list 'action action) (list 'condition condition)) list (list (make-letrec (list (list 'iter (make-lambda (list) (list (make-if (make-application 'condition (list) ) (make-begin (list (make-application 'action (list)) (make-application 'iter (list)))) '(quote ok)))))) list (list (make-application 'iter (list)))))))))) (define while->iteration-expression (lambda (exp) (let ((condition (make-lambda (list) (list (while-pred exp)))) (action (make-lambda (list) (list (while-body exp))))) derive (derive (make-let (list (list 'action action) (list 'condition condition)) list (list (make-letrec (list (list 'iter (make-lambda (list) (list (make-if (make-application 'condition (list) ) (make-begin (list (make-application 'action (list)) (make-application 'iter (list)))) '(quote ok)))))) list (list (make-application 'iter (list)))))))))) 17 (option A) (option A) Adding while as a derived expression We construct a let exp which is a derived exp itself. The body of a let exp / letrec exp may include several expressions (just as the body of a lambda exp). Therefore, the body argument for Make-let, make-letrec, is wrapped within a list.

18 (define special-form? (lambda (exp) (while? exp) (or (quoted? exp) (lambda? exp) (definition? exp) (if? exp) (begin? exp) (while? exp)))) (define special-form? (lambda (exp) (while? exp) (or (quoted? exp) (lambda? exp) (definition? exp) (if? exp) (begin? exp) (while? exp)))) (define eval-special-form (lambda (exp env) ((while? exp) (eval-while exp env)) (cond …((while? exp) (eval-while exp env))))) (define eval-special-form (lambda (exp env) ((while? exp) (eval-while exp env)) (cond …((while? exp) (eval-while exp env))))) 1. Add to special-form?. 2. Add an eval-special-form procedure (option B) (option B) Adding while as a special form Imperative Programming Evaluator: Adding while expressions 3. Add an eval-while procedure (define eval-while (lambda (exp env) (let ( (pred (while-pred exp)) (body (while-body exp))) (letrec ( (iter (lambda () (if (env-eval pred env) (begin (env-eval body env) (iter)) 'ok)))) (iter)))) (define eval-while (lambda (exp env) (let ( (pred (while-pred exp)) (body (while-body exp))) (letrec ( (iter (lambda () (if (env-eval pred env) (begin (env-eval body env) (iter)) 'ok)))) (iter)))) 18

19 (define analyze-special-form (lambda (exp) (cond …((while? exp) (analyze-while exp))))) (define analyze-special-form (lambda (exp) (cond …((while? exp) (analyze-while exp))))) (define analyze-while (lambda (exp) (let ( (pred (analyze (while-pred exp))) (body (analyze (while-body exp)))) (lambda (env) (letrec ((iter (lambda() (if (pred env) (begin (body env) (iter)) 'ok)))) (iter))))) (define analyze-while (lambda (exp) (let ( (pred (analyze (while-pred exp))) (body (analyze (while-body exp)))) (lambda (env) (letrec ((iter (lambda() (if (pred env) (begin (body env) (iter)) 'ok)))) (iter))))) 1. Add to analyze-special-form 2. Add an analysis procedure: (option B) (option B) Adding while as a special form Imperative Programming Evaluator: Adding while expressions 19 Adding while to the compiler as a special form: The eval-while code has been translated to an analyzer code according to two simple rules: 1.Recursive application of analyze to the components of the expression. 2.Currying to produce a procedure that is ready for execution once an environment is given.

20 (define eval-while (lambda (exp env) (let ( (pred (while-pred exp)) (body (while-body exp))) (if (env-eval pred env) (begin (env-eval body env) (eval-while exp env)) 'ok)))) (define eval-while (lambda (exp env) (let ( (pred (while-pred exp)) (body (while-body exp))) (if (env-eval pred env) (begin (env-eval body env) (eval-while exp env)) 'ok)))) Imperative Programming Evaluator: Adding while expressions 20 Not every evaluation procedure can be adjusted to the analyzer by the rules of Recursive application of analyze to the expression components and currying. The following code will correctly evaluate while expressions but cannot be adjusted to the analyzer by the rules noted above: This code cannot be translated to an analyzer code by the above two rules: It involves a recursive call to eval-while which is performed during runtime. Analysis is performed during static time.


Download ppt "Imperative Programming: Mutable data (local state, letrec, set!) Example 1: counter (define counter (let ((count 0)) (lambda () (set! count (+ count 1))"

Similar presentations


Ads by Google