Download presentation
Presentation is loading. Please wait.
Published byBarry Lawrence Modified over 6 years ago
1
Lecture 14 - Environment Model (cont.) - Mutation - Stacks and Queues
מבוא מורחב - שיעור 14
2
Example: explaining make-counter
Counter: something which counts up from a number (define make-counter (lambda (n) (lambda () (set! n (+ n 1)) n ))) (define ca (make-counter 0)) (ca) ==> 1 (ca) ==> 2 (define cb (make-counter 0)) (cb) ==> 1 (ca) ==> 3 (cb) ==> 2 2
3
(define ca (make-counter 0)) | GE
p: n b:(lambda () (set! n (+ n 1)) n) make-counter: ca: E1 n: 0 environment pointer points to E1 because the lambda was evaluated in E1 p: b:(set! n (+ n 1)) n (lambda () (set! n (+ n 1)) n) | E1 3
4
(ca) | GE ==> 1 GE p: n b:(lambda () (set! n (+ n 1)) n)
make-counter: E1 n: 0 p: b:(set! n (+ n 1)) n ca: 1 E2 empty (set! n (+ n 1)) | E2 n | E2 ==> 1 4
5
(ca) | GE ==> 2 GE p: n b:(lambda () (set! n (+ n 1)) n)
make-counter: E1 n: 0 p: b:(set! n (+ n 1)) n ca: 1 2 E3 empty (set! n (+ n 1)) | E3 n | E3 ==> 2 5
6
(define cb (make-counter 0)) | GE
p: n b:(lambda () (set! n (+ n 1)) n) make-counter: E1 n: 2 p: b:(set! n (+ n 1)) n ca: E3 cb: E4 n: 0 p: b:(set! n (+ n 1)) n (lambda () (set! n (+ n 1)) n) | E4 6
7
(cb) | GE ==> 1 n: 0 E4 p: b:(set! n (+ n 1)) n cb: GE
p: n b:(lambda () (set! n (+ n 1)) n) make-counter: E1 n: 2 p: b:(set! n (+ n 1)) n ca: E2 1 E5 7
8
Capturing state in local frames & procedures
p: b:(set! n (+ n 1)) n cb: GE p: n b:(lambda () (set! n (+ n 1)) n) make-counter: E1 n: 2 p: b:(set! n (+ n 1)) n ca: E2 8
9
Lessons from the make-counter example
Environment diagrams get complicated very quickly Rules are meant for the computer to follow, not to help humans A lambda inside a procedure body captures the frame that was active when the lambda was evaluated this effect can be used to store local state 9 9
10
Explaining Nested Definitions
Nested definitions : block structure (define (sqrt x) (define (good-enough? guess) (< (abs (- (square guess) x)) 0.001)) (define (improve guess) (average guess (/ x guess))) (define (sqrt-iter guess) (if (good-enough? guess) guess (sqrt-iter (improve guess)))) (sqrt-iter 1.0)) מבוא מורחב - שיעור 13 10 10
11
p: x b:(define good-enou ..) (define improve ..) sqrt:
(sqrt 2) | GE GE p: x b:(define good-enou ..) (define improve ..) (define sqrt-iter ..) (sqrt-iter 1.0) sqrt: E1 x: 2 good-enough: p: guess b:(< (abs ….) The same x in all subprocedures improve: sqrt-iter: guess: 1 sqrt-iter guess: 1 good-enou? מבוא מורחב - שיעור 13 11 11
12
message passing example
(define (cons x y) (define (dispatch op) (cond ((eq? op 'car) x) ((eq? op 'cdr) y) (else (error "Unknown op -- CONS" op)))) dispatch) (define (car x) (x 'car)) (define (cdr x) (x 'cdr)) This code was modeled on the board. Recall that we explained that this example shows how Scheme’s “static scoping” comes to play. By this we mean that even though the procedure dispatch Pointed to by “a” is called from within the car procedure, our static scoping model that looks for variables in the env the procedure was defined in, causes us to look for x in the env where dispatch was Created, and thus we find the correct variable x to return, the one with value 1. (define a (cons 1 2)) (car a) מבוא מורחב - שיעור 13 12 12
13
(define a (cons 1 2)) | GE cons: car: cdr: GE a: E1 x: 1 y: 2
p: x y b:(define (dispatch op) ..) dispatch cons: car: cdr: a: E1 x: 1 y: 2 p: x b:(x ‘car) p: x b:(x ‘cdr) dispatch: p: op b:(cond ((eq? op 'car) x) .... ) מבוא מורחב - שיעור 13 13 13
14
(car a) | GE ==> 1 cons: car: cdr: GE a: E1 x: 1 y: 2 dispatch: E2
p: x y b:(define (dispatch op) ..) dispatch cons: car: cdr: a: x: E2 E1 x: 1 y: 2 p: x b:(x ‘car) p: x b:(x ‘cdr) dispatch: op: ‘car E3 p: op b:(cond ((eq? op 'car) x) .... ) (x ‘car) | E2 (cond ..) | E3 ==> 1 מבוא מורחב - שיעור 13 14 14
15
Mutating Compound Data
constructor: (cons x y) creates a new pair p selectors: (car p) returns car part of pair (cdr p) returns cdr part of pai mutators: (set-car! p new-x) changes car pointer in pair (set-cdr! p new-y) changes cdr pointer in pair ; Pair × anytype undef -- side-effect only! set-car! and set-cdr! are procedures, while set! is a special form מבוא מורחב - שיעור 14
16
Example: Pair/List Mutation
(define a (list ‘red ‘blue)) red blue b a 10 X a ==> (red blue) (define b a) b ==> (red blue) (set-car! a 10) a ==> (10 ‘blue) b ==> (10 ‘blue) מבוא מורחב - שיעור 14
17
Compare this with… red blue c 10 X d (define c (list ‘red ‘blue))
(define d (list ‘red ‘blue)) red blue c 10 X d c ==> (red blue) d ==> (red blue) (set-car! c 10) c ==> (10 blue) d ==> (red blue) מבוא מורחב - שיעור 14
18
Equivalent vs. The Same In the first example a and b are the same.
A change to one changes the other. They point to a single object. red blue b a 10 X In the second example c and d have at first the same value, but later on one changes and the other does not.They just happen to have at some point in time the same value. red blue c 10 X d red blue Without mutation, there is no “identity”: equality of value is all we have מבוא מורחב - שיעור 14
19
Example 2: Pair/List Mutation
(define x (list 'a 'b)) (set-car! (cdr x) (list 1 2)) Eval (cdr x) to get a pair object Change car pointer of that pair object a b x X 2 1 (a ( 1 2)) מבוא מורחב - שיעור 14
20
Can create cyclic structures
(define x (list 1 2)) (cddr x) ==> () 1 2 x (set-cdr! (cdr x) x) (caddr x) ==> 1 Beware of infinite scanning (or printing). Dr. Scheme prevents the infinite printing of returned values (sometimes). Prints some indication: x ==> #0=(1 2 . #0#) מבוא מורחב - שיעור 14
21
Eq? vs. Equal? To check whether two names point to the same object:
Test with eq? (eq? a b) ==> #t To check whether two elements currently have the same content: Test with equal? (equal? (list 1 2) (list 1 2)) ==> #t (eq? (list 1 2) (list 1 2)) ==> #f מבוא מורחב - שיעור 14
22
Lets go over the following:
x ==> (3 4) y ==> (1 2) (set-car! x y) x ==> (set-cdr! y (cdr x)) (set-cdr! x (list 7) 7 X 3 4 x ((1 2) 4) X X ((1 4) 4) 1 2 y ((1 4) 7) מבוא מורחב - שיעור 14
23
We can actually get away only with set!
(define (cons x y) (define (change-car val) (set! x val)) (define (change-cdr val) (set! y val)) (lambda (m) (cond ((eq? m 'car) x) ((eq? m 'cdr) y) ((eq? m 'set-car!) change-car) ((eq? m 'set-cdr!) change-cdr) (else (error "Undefined operation“ m))))) מבוא מורחב - שיעור 14
24
We can actually get away only with set!
(define (car z) (z 'car)) (define (cdr z) (z 'cdr)) (define (set-car! z new-value) ((z 'set-car!) new-value) z) (define (set-cdr! z new-value) ((z 'set-cdr!) new-value) Saw that pairs can be implemented with functions. Now we see that pair mutation can be implemented with functions and set! But set! is an essential addition. מבוא מורחב - שיעור 14
25
Stack Data Abstraction
Insert Insert Last in, First out. Insert Delete Insert מבוא מורחב - שיעור 14
26
Stack Data Abstraction
constructor: (make-stack) returns an empty stack selectors: (top stack) returns current top element from a stack operations: (insert stack elem) returns a new stack with the element added to the top of the stack (push) (delete stack) returns a new stack with the top element removed from the stack (pop) (empty-stack? stack) returns #t if no elements, #f otherwise contract: (delete stack) require (not (empty-stack? stack)) (top stack) require (not (empty-stack? stack)) ensure (equal? (delete (insert stack elem)) stack) ensure (equal? (top (insert stack elem)) elem) מבוא מורחב - שיעור 14
27
Stack Implementation Strategy
implement a stack as a list a b d we will insert and delete items at the front of the stack מבוא מורחב - שיעור 14
28
Stack Implementation (define (make-stack) nil)
(define (empty-stack? stack) (null? stack)) (define (insert stack elem) (cons elem stack)) (define (delete stack) (if (empty-stack? stack) (error "stack underflow – delete") (cdr stack))) (define (top stack) (error "stack underflow – top") (car stack))) מבוא מורחב - שיעור 14
29
Limitations in our Stack
Stack does not have identity (define s (make-stack)) s ==> () (insert s 'a) ==> (a) (set! s (insert s 'b)) s ==> (b) מבוא מורחב - שיעור 14
30
Mutable Stack Implementation
The stack will be a mutable data type. The data type contains a list of elements – as before. Insert and delete mutate a stack object. The first element of the list is special to distinguish Stack objects from other lists – defensive programming X (delete! s) a c d stack s מבוא מורחב - שיעור 14
31
Mutable Stack Data Abstraction
constructor: (make-stack) returns an empty stack queries (selectors): (top stack) returns current top element from a stack (empty-stack? stack) returns #t if no elements, #f otherwise (stack? any) returns #t if any is a stack, #f otherwise command (mutators, transformers): (insert! stack elem) modify the stack by adding elem to the top of the stack (push) (delete! stack) modify the stack by removing the top element from the stack (pop) stack? is really not part of the stack abstraction מבוא מורחב - שיעור 14
32
Mutable Stack Implementation (1)
(define (make-stack) (cons 'stack nil)) (define (stack? stack) (and (pair? stack) (eq? 'stack (car stack)))) (define (empty-stack? stack) (null? (cdr stack))) (define (top stack) (if (empty-stack? stack) (error "stack underflow – top") (cadr stack))) מבוא מורחב - שיעור 14
33
Mutable Stack Implementation (2)
(define (insert! stack elem) (set-cdr! stack (cons elem (cdr stack))) stack)) (define (delete! stack) (if (empty-stack? stack) (error "stack underflow – delete") (set-cdr! stack (cddr stack))) stack) Here the mutators return the stack. May choose to return a neutral value, eg. ‘ok or nothing (more later) מבוא מורחב - שיעור 14
34
Mutatable vs. functional
The decision between a mutable stack and a functional stack is part of the contract Changing this changes the abstraction! The user should know if the object mutates or not in order to use the abstraction correctly: For example, if we write (define stack1 stack2) can stack1 later change because of changes to stack2 ? מבוא מורחב - שיעור 14
35
A Queue Insert Insert FIFO: First In, First Out Insert x1 x2 x3 front
מבוא מורחב - שיעור 14
36
A Queue Insert Insert FIFO: First In, First Out Insert Delete x2 x3
front מבוא מורחב - שיעור 14
37
A Queue Implementation
A queue is a list of queue elements: c d b The front of the queue is the first element in the list To insert an element at the tail of the queue, need to scan the entire list, then attach the new element at the rear: b c d new מבוא מורחב - שיעור 14
38
A Queue Implementation (Cont)
(define (make-queue) null) (define (empty-queue? q) (null? q)) (define (front-queue q) (if (empty-queue? q) (error "front of empty queue:" q) (car q))) (define (delete-queue q) (error "delete of empty queue:" q) (cdr q))) (define (insert-queue q elt) (cons elt nil) (cons (car q) (insert-queue (cdr q) elt)))) מבוא מורחב - שיעור 14
39
Complexity of the implementation
For a queue of length n Time required -- number of cons, car, cdr calls? Space required -- number of new cons cells? front-queue, delete-queue: Time: T(n) = Θ(1) that is, constant in time Space: S(n) = Θ(1) that is, constant in space insert-queue: Time: T(n) = Θ (n) that is, linear in time Space: S(n) = Θ(n) that is, linear in space מבוא מורחב - שיעור 14
40
Mutable Queue Data Abstraction
constructor: (make-queue) returns an empty queue queries (selectors, assessors): (front-queue q) returns the object at the front of the queue. If queue is empty signals error (empty-queue? q) tests if the queue is empty commands (mutators, transformers) : (insert-queue! q elt) inserts the elt at the rear of the queue and returns ‘ok (delete-queue! q) removes the elt at the front of the queue and returns ‘ok additional query: (queue? q) tests if the object is a queue מבוא מורחב - שיעור 14
41
Implementation We attach a type tag as before. Maintain queue identity
Build a structure to hold: a list of items in the queue a pointer to the front of the queue a pointer to the rear of the queue queue c d b a front-ptr rear-ptr מבוא מורחב - שיעור 14
42
Queue Helper Procedures
Hidden inside the abstraction (define (front-ptr q) (cadr q)) (define (rear-ptr q) (cddr q)) (define (set-front-ptr! q item) (set-car! (cdr q) item)) (define (set-rear-ptr! q item) (set-cdr! (cdr q) item)) queue c d b a front-ptr rear-ptr מבוא מורחב - שיעור 14
43
Queue implementation (define (make-queue)
(cons 'queue (cons null null))) (define (queue? q) (and (pair? q) (eq? 'queue (car q)))) (define (empty-queue? q) (if (not (queue? q)) (error "object not a queue:" q) (null? (front-ptr q)))) (define (front-queue q) (if (empty-queue? q) (error "front of empty queue:" q) (car (front-ptr q)))) מבוא מורחב - שיעור 14
44
Queue implementation – Insert
(define (insert-queue! q elt) (let ((new-pair (cons elt nil))) (cond ((empty-queue? q) (set-front-ptr! q new-pair) (set-rear-ptr! q new-pair) ‘ok) (else (set-cdr! (rear-ptr q) new-pair) ‘ok)))) rear-ptr e new-pair queue c d b a front-ptr rear-ptr מבוא מורחב - שיעור 14
45
Queue implementation - delete
(define (delete-queue! q) (cond ((empty-queue? q) (error "delete of empty queue:" q)) (else (set-front-ptr! q (cdr (front-ptr q))) ‘ok))) queue c d b a front-ptr rear-ptr מבוא מורחב - שיעור 14
46
Time and Space complexities ?
מבוא מורחב - שיעור 14
47
Programming Styles – Procedural vs. Object-Oriented
Procedural programming - Organize system around procedures that operate on data: (do-something <data> <arg> ...) (do-another-thing <data>) Object-based programming - Organize system around objects that receive messages ((<object> 'do-something) <arg>) ((<object> 'do-another-thing) ... ) An object encapsulates data and operations Message passing and returned procedures are the means to write object oriented code in scheme מבוא מורחב - שיעור 14
48
Stacks in OO style (define (make-stack) (let ((top-ptr '()))
(define (empty?) (null? top-ptr)) (define (delete!) (if (null? top-ptr) (error . . .) (set! top-ptr (cdr top-ptr))) top-ptr ) (define (insert! elmt) (set! top-ptr (cons elmt top-ptr)) top-ptr) (define (top) (if (null? top-ptr) (error . . .) (car top-ptr))) (define (dispatch op) (cond ((eq? op 'empty?) empty?) ((eq? op 'top) top) ((eq? op 'insert!) insert!) ((eq? op 'delete!) delete!))) dispatch)) מבוא מורחב - שיעור 14
49
(define (insert! s ‘a) ((s insert!) ‘a))
Stacks in OO style (define s (make-stack)) ((s 'insert!) 'a) ==> ((s 'insert!) 'b) ==> ((s 'top)) ==> ((s 'delete!)) ==> (a) (b a) b (a) a () compare with message passing examples: in OO we do not hide behind a functional layer eg. (define (insert! s ‘a) ((s insert!) ‘a)) In OO programming languages the notation is eg. s.insert(a) s.delete() מבוא מורחב - שיעור 14
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.