Download presentation
Presentation is loading. Please wait.
1
Lecture 14: The environment model (cont
Lecture 14: The environment model (cont.) Mutators for compound data (Section 3.3, pages ) Stack; Queue
2
Example: explaining make-counter
Counter: something which counts up from a number (define (make-counter 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
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
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
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
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
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
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
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
10
Lets do a 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)
11
(define (cons x y) ..) | GE GE p: x,y b:(def disp (op) .. dispatch)
b:(x ‘cdr) cdr: p: x b:(x ‘car) car:
12
(define a (cons 1 2)) | GE GE p: x,y b:(def disp (op) .. dispatch)
b:(x ‘car) car: cdr: a: E1 x: 1 Y: 2 p: op b:(cond ..) Disp: p: x b:(x ‘cdr)
13
(car a) | GE GE p: x,y b:(def disp (op) .. dispatch) cons: p: x
b:(x ‘car) car: cdr: a: x: E2 E1 x: 1 Y: 2 p: op b:(cond ..) Disp: p: x b:(x ‘cdr)
14
(x ‘car) | E2 GE p: x,y b:(def disp (op) .. dispatch) cons: p: x
b:(x ‘car) car: cdr: a: x: E1 x: 1 Y: 2 E2 p: op b:(cond ..) Disp: E3 empty p: x b:(x ‘cdr)
15
Returned value is x|E1=1. After that what remains is:
GE p: x,y b:(def disp (op) dispatch) cons: p: x b:(x ‘car) car: cdr: a: E1 x: 1 Y: 2 p: op b:(cond ..) Disp: p: x b:(x ‘cdr)
16
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))
17
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: guess: 1 good-enou? E1 x: 2 good-enough: p: guess b:(< (abs ….) The same x in all subprocedures improve: sqrt-iter: guess: 1 sqrt-iter
18
Summary: The Environment Model
A precise, completely mechanical description of: name-rule looking up the value of a variable define-rule creating a new definition of a var set!-rule changing the value of a variable lambda-rule creating a procedure application rule applying a procedure You will use it to implement the Scheme interpreter, Gotta practice using it… It’s a major part of the final exam As we noted earlier in the course, we need to change models to explain a more complex universe, in the same way that in Physics one needs to abandon the Newtonian model in order to reason effectively about sub-atomic particles.
19
Mutators for compound data
20
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 pair 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!
21
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)
22
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)
23
Equivalent vs. The Same In the first example a and b are the same.
A change to one changes the other. The 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
24
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
25
Q&A: “2 B 2 B =” Q: If we change an object, is it the same object?
A: Yes, if we retain the same pointer to the object. Q: How can we tell if two elements share the same object? A. One thing you can do is mutate one and see if the other also changes.
26
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 2 1 (a ( 1 2))
27
Your Turn 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)
28
Summary Scheme provides built-in mutators set! to change a binding
set-car! and set-cdr! to change a pair Mutation introduces substantial complexity Unexpected side effects Substitution model is no longer sufficient to explain behavior
29
Stack
30
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 (delete stack) returns a new stack with the top element removed from the stack (empty-stack? stack) returns #t if no elements, #f otherwise
31
Stack Data Abstraction
Insert Insert Last in, First out. Insert Delete Insert
32
Stack Contract If s is a stack, created by (make-stack)and subsequent stack procedures, where i is the number of insertions and d is the number of deletions, then If d>i then it is an error If d=i then (empty-stack? s) is true, and (top s) and (delete s) are errors. If d<i then (empty-stack? s) is false and (top (delete (insert s val))) = (top s) If d<=i then (top (insert s val)) = val for any val
33
Stack Implementation Strategy
implement a stack as a list a b d we will insert and delete items at the front of the stack
34
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)))
35
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)
36
Alternative 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
37
Alternative Stack Implementation (1)
(define (make-stack) (cons 'stack nil)) (define (stack? stack) (and (pair? stack) (eq? 'stack (car stack)))) (define (empty-stack? stack) (if (not (stack? stack)) (error "object not a stack:" stack) (null? (cdr stack)))) (define (top stack) (if (empty-stack? stack) (error "stack underflow – top") (cadr stack)))
38
Alternative Stack Implementation (2)
(define (insert! stack elem) (cond ((not (stack? stack)) (error "object not a stack:" stack)) (else (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)
39
Does the user have to know about it?
Usually the user does not care about the implementation As long as the contract is being kept. Both implementations keep the contract. Yet: This is a change to the abstraction! The user should know if the object mutates or not in order to use the abstraction correctly. If we (define a b), can a later change because of changes to b?
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.