Download PS14

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Stream processing wikipedia , lookup

Logic programming wikipedia , lookup

Subroutine wikipedia , lookup

Programming language wikipedia , lookup

C Sharp syntax wikipedia , lookup

Recursion (computer science) wikipedia , lookup

One-pass compiler wikipedia , lookup

Go (programming language) wikipedia , lookup

Abstraction (computer science) wikipedia , lookup

C++ wikipedia , lookup

Falcon (programming language) wikipedia , lookup

CAL Actor Language wikipedia , lookup

C Sharp (programming language) wikipedia , lookup

Structured programming wikipedia , lookup

Object-oriented programming wikipedia , lookup

Corecursion wikipedia , lookup

Reactive programming wikipedia , lookup

Functional programming wikipedia , lookup

Transcript
Imperative Programming: Mutable data (local state, letrec, set!)
Example 1: counter
(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
Imperative Programming: Mutable data (local state, letrec, set!)
Example 1: counter
(define counter
(let ((count 0))
(lambda () (set! count (+ count 1))
count)))
GE
counter
E2
E1
count=0 1
(lambda () (set!...
P = count
B= (lambda () (set!...
count
P=
B= (set!...
count
(set!...
count
• 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
> (counter)
2 2
Imperative Programming: Mutable data (local state, letrec, set!)
Example 2: A chess player object:
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.
(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)))
3
We’ll examine a simpler
representation of a chess
player by using only the
procedure set-total.
Imperative Programming: Mutable data (local state, letrec, set!)
Example 2: A chess player object:
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.
(define make-player (lambda (total)
(lambda (piece)
(let ((piece-value (cond ((eq? piece 'queen) 9)
((eq? piece 'rook) 5)
((eq? piece 'bishop) 3)
Local state (initialized)
((eq? piece 'knight) 3)
((eq? piece 'pawn) 1)
(else 0))))
(set! total (- total piece-value))
total))))
((make-player 39) ‘queen)
GE
make-player
4
E1
total =
39 30
(lambda (piece)…
P=(total)
B=(lambda (piece)…
E2
Piece =
‘queen
(let ((piece-value…
P=(piece)
B=(let ((piece-value…
E3
piece-value =
9
(set! total (- total piece-value))
P=(piece-value) total…
B=(set!...
total…
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.
To support the evaluation of a letrec expression, it is handled as a derived expression:
(let
(letrec
((f1 lambda-exp1)
...
(fn lambda-expn))
e1...em)
5
((f1 ’unassigned)
...
(fn ’unassigned))
(set! f1 lambda-exp1)
...
(set! fn lambda-expn)
e1...em)
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
E1
(A)
Params: fact
Body: (set!...
(fact 3)
6
fact='unassigned
(set..
(fact 3)
(B)
Params: n
Body: (if… )
Remains to evaluate… (next slide)
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] ==> <primitive *>
==> env-eval [n,E2]==> 3 (lookup)
==> env-eval[(fact (- n 1)), E2]
==> env-eval[fact, E2]
==> lookup-variable-value(fact,E2): (B) …
GE
E2
E1
(A)
Params: fact
Body: (set!...
(fact 3)
7
fact='unassigned
(set..
(fact 3)
n=3
(B)
…(* n (fact (- n 1)))…
Params: n
Body: (if… )
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]==>
Env-eval[ ( (lambda (fact) (fact 3))
(lambda (n) (if (= n 0) 1 (* n (fact (- n 1))))) ), GE]
(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!
GE
E1
(A)
Params: fact
Body: (set..
(fact 3)
8
fact
(set..
(fact 3)
(B)
Params: n
Body: (if… )
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)
> (define y (list 'e 'f))
> (set-car! x y)
>x
((e f) c d)
Notice the difference from the following:
> (define z (cons y (cdr x)) )
>z
((e f) c d)
>x
((e f) c d)
9
c
a
b
e
f
d
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
#t
d
> (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
e
f
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.
We use a similar idea in the following procedure
; 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.
If from > to, the result is a circular list:
> (modify-list! (list 1 2 3 4) 4 2)
1234234…
If from < to, then list elements are “skipped”:
(define (modify-list! lst from to)
(let ( (f (memq from lst))
(t (memq to lst)) )
(if (and f t) (set-cdr! f t))))
11
>(modify-list! (list 1 2 3 4) 2 4)
124 (non-circular)
Imperative Programming Evaluator: Adding while expressions
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!
In the (Meta-Circular Environment Based) interpreter for imperative programming, support for set!
expressions is added. This gives motivation for supporting while expressions:
> (define x 0)
> (define n 4)
> (while (> n 0)
(begin (set! x (+ x n))
(set! n (- n 1))) )
>x
10
12
Imperative Programming Evaluator: Adding while expressions
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))) )
1
Endless loop…
After the first time pred is evaluated to #t, It
remains #t in every recursive call.
So the answer is?... Yes! BUT, only in the normal evaluation approach.
According to the normal evaluation approach,
(define while (lambda (pred body)
the predicate must be evaluated.
(if pred (begin (body)
(while pred body))))
> (while (> x 0) (lambda () (begin (set! x (+ x n))
(display x))))
1
0
13
The expression constituting pred is pass to
recursive calls, as opposed to the value of the
pred expression in the eager approach.
Imperative Programming Evaluator: Adding while expressions
To support while expressions, we add the appropriate parser procedures:
(define while? (lambda (exp) (tagged-list? exp 'while)))
(define while-pred (lambda (exp)
(car (get-content exp))))
(define while-body (lambda (exp)
(cadr (get-content exp))))
14
Imperative Programming Evaluator: Adding while expressions
(option A) Adding while as a derived expression
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)))))
3. Add the translation procedure: while->iteration-expression…
(while (> n
0) n) 0)
(iter
(begin
x (+n))))
x n))
(set! n (-(set!
n (iter
(set! n (- n 1))))
0) (begin
(letrec ((iter (lambda () (if (> n
(iter
n) 0) (begin (set! x (+ x n))
(set!n))))
n (- n 1)))
(begin (set! n (- n (iter
(iter))
(iter))
‘done))))
(iter))
Any problem with the solution above? There might be if iter is a predefined procedure!
15
Imperative Programming Evaluator: Adding while expressions
(option A) Adding while as a derived expression
3. Add the translation procedure: while->iteration-expression… Second try:
(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)))
16
Imperative Programming Evaluator: Adding while expressions
(option A) Adding while as a derived expression
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
(make-let (list (list 'action action) (list 'condition condition))
(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 (make-application 'iter (list))))))))))
We construct a let
exp which is a
derived exp itself.
17
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.
Imperative Programming Evaluator: Adding while expressions
(option B) Adding while as a special form
1. Add to special-form?.
(define special-form? (lambda (exp)
(or (quoted? exp) (lambda? exp) (definition? exp)
(if? exp) (begin? 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)))
(letrec ( (iter (lambda ()
(if (env-eval pred env)
(begin (env-eval body env)
(iter))
'ok))))
(iter))))
18
Imperative Programming Evaluator: Adding while expressions
(option B) Adding while as a special form
Adding while to the compiler as a special form:
1. Add to analyze-special-form
(define analyze-special-form (lambda (exp)
(cond …((while? exp) (analyze-while exp)))))
2. Add an analysis procedure:
(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)))))
19
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.
Imperative Programming Evaluator: Adding while expressions
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:
(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))))
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.
20