Imperative Programming Mutable data and local state Example
Imperative Programming: Mutable data and local state Example 1: counter (set! vs set-box!) (define counter (let ((count 0)) (lambda () (set! count (+ count 1)) count))) > (counter) 1 > (define count 5) > (counter) 2 E 1 count: 0 1 GE counter (lambda () (set!. . . P = count B = (lambda () (set!. . . o count is the local state of the counter object. o In functional languages, objects are implemented as runtime generated closures. 1 E 2 (set! count. . . P= B = (set! count. . .
Imperative Programming: Mutable data and local state Example 1: counter (set! vs set-box!) > (counter (lambda(x) (set! x (+ x 1)))) 0 (define counter (let ((count 0)) (lambda (modifer) (modifer count))) E 1 count: 0 GE counter E 2 modifier (lambda (modifier). . . P=x B = (set! x. . . E 3 x: 0 1 (set! x. . . 2 P = count B = (lambda (modifier). . . (modifier count)… P = modifier B = (modifier count)…
Imperative Programming: Mutable data and local state Example 1: counter (set! vs set-box!) > (counter (lambda(x) (set-box! x (+ x 1)))) 1 > (counter (lambda(x) (set-box! x (+ x 1)))) 2 (define counter (let ((count (box 0))) (lambda (modifer) (modifer count) (unbox count)))) E 1 count: GE counter 01 E 2 modifier (lambda (modifier). . . P=x B = (set-box! x. . . E 3 x: (set-box! x. . . 3 P = count B = (lambda (modifier). . . (modifier count)… P = modifier B = (modifier count)…
Imperative Programming: Mutable data and local state Example 2: Boxes in Lists (define my-box (box 5)) (define my-list-1 (list 1 my-box 2)) (define my-list-2 (list my-box 4 5)) > my-list-1 '(1 #&5 2) > my-list-2 '(#&5 4 5) my-list-2 >(set-box! (car my-list-2) 'hello) >(set! my-box 'cat) > my-list-1 '(1 #&hello 2) 4 5 llo my-box h 5 e my-list-1 1 What elements of the list can we modify? > (set! (car my-list-1) 3) Error 4 2
Imperative Programming: Mutable data and local state Example 3: Circular Lists o A pseudo-circular lists can be generated as a list where each of its members is a boxed-value. o The value of the last box can be set to the list itself. > (define circ-list (box 1) (box 2) (box 3))) circ-list 1 2 3 > (set-box! (caddr circ-list) circ-list 1 2 o It is only a pseudo-circular because the last member of the list still points to '(). 5
Imperative Programming: Mutable data and local state Example 4: letrec o The letrec expression can be used to define local recursive procedures. o Not supported by the functional programming model (applicative-eval) without rewriting the code. o Can be supported by the imperative programming model (based on the environment model). To support the evaluation of a letrec expression, it is handled as a derived expression: (letrec ((f 1 lambda-exp 1). . . (fn lambda-expn)) e 1. . . em) (let ((f 1 ’unassigned). . . (fn ’unassigned)) (set! f 1 lambda-exp 1). . . (set! fn lambda-expn) e 1. . . em)) 6
Imperative Programming: Mutable data and local state Example 4 (cont’d): The following is an example of a derived letrec expression: (letrec ((fact (lambda (n) (if (= n 0) 1 (* n (fact (- n 1))))))) (fact 3)) (let ((fact 'unassigned)) (set! fact (lambda (n) (if (= n 0) 1 (* n (fact (- n 1)))))) (fact 3)) ((lambda (fact) (set! fact (lambda (n) (if (= n 0) 1 (* n (fact (- n 1)))))) (fact 3)) 'unassigned) 7
Imperative Programming: Mutable data and local state Example 4 (cont’d): Evaluate the following code 1. ((lambda (fact) 2. (set! fact (lambda 3. (if 4. 5. 6. (fact 3)) 8. 'unassigned) (n) (= n 0) 1 (* n (fact (- n 1)))))) GE E 1 fact: 'unassigned P: fact B: (set!. . . (fact 3)) 8 P: n B: (if… ) (set!. . (fact 3)) E 2 n: 3 E 3 n: 2 E 4 n: 1 E 5 n: 0 (if…) (if. . .
Imperative Programming: Mutable data and local state Example 5: The chess player o A chess player object is represent by a dispatch procedure. o Based on a given message it invokes internal procedures of the object. o total and steps are the object’s local state variables. (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) … (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) ((eq? m 'get-steps) ( else (error "Unknown request"))))) ) dispatch))) 10
Imperative Programming: Mutable data and local state Example 5 (cont’d): Evaluate - (define player (make-player 39)) (define make-player (lambda (total) (letrec ((steps 0) (get-steps (lambda () steps)). . . (set-total! (lambda (piece) (let ((piece-value (cond ((eq? piece 'queen) 9) ((eq? piece 'rook) 5). . . (else 0)))) (set! total (- total piece-value))))) (dispatch (lambda (m) (cond ((eq? m 'set-total) set-total!). . . ( else (error "Unknown request"))))) ) dispatch))) GE make-player E 1 total: 39 ( (lambda (steps… P= total B= ( (lambda (steps… 12 E 2 Steps : ‘unassigned 0 get-steps: ‘unassigned … dispatch: ‘unassigned P= steps, get-steps …dispatch B= (set! steps…. . . dispatch)) P= B= steps P=m B=(cond…
Imperative Programming: Mutable data and local state Example 5 (cont’d): Evaluate - ((player 'set-total) 'queen)) (define make-player (lambda (total) (letrec ((steps 0) (get-steps (lambda () steps)). . . (set-total! (lambda (piece) (let ((piece-value (cond ((eq? piece 'queen) 9) ((eq? piece 'rook) 5). . . (else 0)))) (set! total (- total piece-value))))) (dispatch (lambda (m) (cond ((eq? m 'set-total) set-total!). . . ( else (error "Unknown request"))))) ) dispatch))) GE make-player E 1 total: 3930 ( (lambda (steps… P= total B= ( (lambda (steps… 13 (set! total… E 2 Steps : ‘unassigned 0 get-steps: ‘unassigned … dispatch: ‘unassigned P= steps, get-steps …dispatch B= (set! steps…. . . dispatch)) P= B= steps P=m B=(cond… E 3 m = ‘set-total (cond… E 5 Piece-value: 9 E 4 piece : ‘queen (let… P= piece-value B= (set! total…
Imperative Programming: Adding while Example 6: In the imperative programming evaluator, support for box, unbox, set-box! expressions is added, which motivates supporting while expressions: Syntax: (while <predicate> <body>). > (derive-eval '(define x 0)) > (derive-eval '(define n 4)) > (derive-eval '(while (> n 0) > (derive-eval x 10 (begin (set! x (+ x n)) (set! n (- n 1))))) t-g-e) Q: Can a while expression be supported in a functional programming evaluator? A: NO! in functional programming there is no change of state. Particularly, the result of evaluating the <predicate> clause of a while loop will always remain the same. An ability to change state is required! 15
Imperative Programming: Adding while Example 6 (cont’d): First, add the relevant parser procedures: while? (exp) while-pred (exp) while-body (exp) make-while (exp) 16 ; ; returns creates true iff exp is a while exp. the predicate of a while exp. the body of a while exp.
Imperative Programming: Adding while – As a derived expression Example 6 (cont’d): 1. Add to derived? (define derived? (lambda (exp) (or. . . (while? exp)))) 2. Add to shallow-derive (define shallow-derive (lambda (exp) (cond. . . ((while? exp) (while->iteration-expression exp))))) 17
Imperative Programming: Adding while – As a derived expression Example 6 (cont’d): Writing the translation procedure, first try: 3. Add the translation procedure: while->iteration-expression… (while (> n 0) (begin (set! x (+ x n)) (set! n (- n 1)))) (letrec ((iter (lambda () (if (> n 0) (begin (set! x (+ x n)) (set! n (- n 1))) (iter)) 'ok)))) (iter)) Q: Any problem with the suggested translation? 18
Imperative Programming: Adding while – As a derived expression Example 6 (cont’d): Writing the translation procedure, first try: 3. Add the translation procedure: while->iteration-expression… (define iter (lambda (x) x)) (while (> (iter n) 0) (set! n (- n (iter n)))) (letrec ((iter (lambda () (if (> (iter n) 0) (begin (set! n (- n (iter n))) (iter)) 'ok)))) (iter)) Q: Any problem with the suggested translation? There might be if iter is a predefined procedure! 19
Imperative Programming: Adding while – As a derived expression Example 6 (cont’d): Writing the translation procedure, second try: 3. Add the translation procedure: while->iteration-expression… (define iter (lambda (x) x)) (while (> (iter n) 0) (set! n (- n (iter n)))) (let ((pred (lambda () (> (iter n) 0))) (body (lambda () (set! n (- n (iter n)))))) (letrec ((iter (lambda () (if (pred) (begin (body) (iter)) 'ok)))) (iter))) 20
Imperative Programming: Adding while – As a derived expression Example 6 (cont’d): The translation procedure (define while->iteration-expression (lambda (exp) (let ((pred (make-lambda ‘() (list (while-pred exp)))) (body (make-lambda ‘() (list (while-body exp))))) (make-let (list ‘pred) (list ‘body)) (list (make-letrec (list 'iter (make-lambda (list) (list (make-if (make-application ‘pred (list)) (make-begin (list (make-application ‘body (list)) (make-application 'iter (list)))) '(quote ok)))))) (list (make-application 'iter (list))))) 21
Imperative Programming: Adding while – As a special form Example 6 (cont’d): 1. Add to special-form? . (define special-form? (lambda (exp) (or (quoted? exp). . . (while? exp)))) 2. Add an eval-special-form procedure (define eval-special-form (lambda (exp env) (cond. . . ((while? exp) (eval-while exp env))))) 3. Add an eval-while procedure (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)))) 22
Imperative Programming: Adding while – As a special form Example 6 (cont’d): Adding while to the compiler as a special form 1. Add to special-form? . (define analyze-special-form (lambda (exp) (cond. . . ((while? exp) (analyze-while exp))))) 2. Make analysis of the expression components. Rules of thumb are: a. Recursively analyze the exp components. b. Curry to produce a ready-to-execute procedure. (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 analyze-while (lambda (exp) (let ((pred (analyze (while-pred exp))) (body (analyze (while-body exp)))) (lambda (env) (if (pred env) b (begin (body env) ((analyze-while exp) env)) 'ok))))) BIG NO-N O! The use (a) and (b) to translate evaluator code to analyzer code requires the evaluator code to be written properly. The translated code should not include calls to eval or produce new code. 23 a
Imperative Programming: Adding while – As a special form Example 6 (cont’d): Adding while to the compiler as a special form 1. Add to special-form? . (define analyze-special-form (lambda (exp) (cond. . . ((while? exp) (analyze-while exp))))) 2. Make analysis of the expression components. Rules of thumb are: a. Recursively analyze the exp components. b. Curry to produce a ready-to-execute 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 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)))))) o When using evaluator code for the purpose of adjusting it to the analyzer, eval 24 must not be part of the computation, and should not produce new code.
- Slides: 21