Com S 342 meeting -*- Outline -*- * sharing (4.6) ------------------------------------------ SHARING (4.6) > (define a (cons 1 (cons 2 '()))) > (define b (cons (cons 3 '()) (cons 4 (cons 5 '())))) > (define c (cons a (cdr b))) > (set-car! (cdr b) a) > (eq? (car (cdr b)) a) ------------------------------------------ Draw picture (like figure 11.16 in SAP) be sure to use boxes for the variables a, b, and c! Note how the objects are shared. This has been happening all along but we haven't had to worry about it, because we haven't changed the lists draw what happens if we do (set-car! (cdr b) a)? note that set-car! doesn't have to take a variable as an arg. note that now (eq? (car (cdr b)) a) is true Q: Can you draw what happens if we do (set-car! b a)? now (equal? c b) but not (eq? c b) ------------------------------------------ > (define a (cons 1 (cons 2 '()))) > (define b (cons (cons 3 '()) (cons 4 (cons 5 '())))) > (define c (cons a (cdr b))) > (set-car! b a) > (equal? c b) > (eq? c b) a: [ *--]--->[ * | *-]--> [ * | *-]--> () ^ | | | v v | 1 2 \ \ \ c: [ *--]--->[ * | * ] \ \ \ b: [ *--]--->[ * | * ] | / \ / v vv [ * | * ] [ * | *-]-->[ * | * ] | | | | | v v v v v 3 () 4 5 () ------------------------------------------ ------------------------------------------ CIRCULARITY (define f (cons 1 '())) > (set-cdr! f f) > f ------------------------------------------ warning: circular lists don't always print well! ** append! This is like reverse! in the book we can use set-cdr! to write a more space and time efficient and dangerous version of append... ------------------------------------------ DANGEROUS APPEND! (define append! ;;TYPE:(-> ((list T) (list T)) (list T)) (lambda (ls1 ls2) ;; MODIFIES: ls1 ;; EFFECT: modify ls1 to have the ;; elements of ls1 followed by ls2's (define last-pair ;; TYPE: (-> ((nonempty-list T)) ;; (pair T (list T))) (lambda (x) (if (null? (cdr x)) x (last-pair (cdr x))))) ------------------------------------------ ... (if (null? ls1) ls2 (begin (set-cdr! (last-pair ls1) ls2) ls1)))) ------------------------------------------ EXAMPLE OF APPEND! > (define c (list 3 4)) > (define d (list 2)) > (define y (append! c d)) c: [ *--]--->[ * | *-]--> [ * | *-]--> () | | v v 3 4 d: [ *--]--->[ * | *-]--> () | v 2 ------------------------------------------ Q: What is c? d? y? Q: After executing append! what are c? d? y? Q: Is it any different if we execute (define y (append! (cdr c) d))? ------------------------------------------ EXAMPLE OF APPEND! > (define c (list 3 4)) > (define d (list 2)) > (define y (append! (cdr c) d)) c: [ *--]--->[ * | *-]--> [ * | *-]--> () | | v v 3 4 d: [ *--]--->[ * | *-]--> () | v 2 ------------------------------------------ Q: What if we use append instead of append!? ------------------------------------------ RECALL THE SAFE APPEND PROCEDURE (define append ;; TYPE: (-> ((list T) (list T)) ;; (list T)) (lambda (ls1 ls2) (if (null? ls1) ls2 (cons (car ls1) (append (cdr ls1) ls2))))) ------------------------------------------ ------------------------------------------ USING APPEND INSTEAD > (define c (list 3 4)) > (define d (list 2)) > (define y (append c d)) c: [ *--]--->[ * | *-]--> [ * | *-]--> () | | v v 3 4 d: [ *--]--->[ * | *-]--> () | v 2 ------------------------------------------ ** what define and set! do ------------------------------------------ DEFINE AND SET! (define a (cons 3 '())) ___ _____ _____ ____ a:[ --]----------> | | --|--> |_()_| |__|__|_____| | | _v_ |_3_| (set! a (cons 4 (cons 5 '()))) ------------------------------------------ Draw the picture of the evaluation of the set! ------------------------------------------ NESTED DEFINES VS. SET (define a (cons 3 '())) (define a-set! ;; TYPE: (-> ((list number)) ;; (list number)) (lambda (lon) (define a lon) lon)) (a-set! (cons 2 '())) ___ _____ _____ ____ a:[ --]----------> | | --|--> |_()_| |__|__|_____| | | _v_ |_3_| ------------------------------------------ To make it work to change a, you'd have to change the define to set! ** garbage At this point, the cons cell (cons 3 '()) is garbage. garbage objects are not reachable from program variables. non-garbage objects are reachable from program variables. Q: How is this handled in Scheme? C++? Java? Which is better? ** using set! and local bindings to make objects. ------------------------------------------ AN OO STACK ADT > (send a-stack 'push! 1) > (send a-stack 'push! 2) > (send a-stack 'top) > (send a-stack 'pop!) > (send a-stack 'top) > (send a-stack 'pop!) In C++ syntax, how would you write (send a-stack 'push! 1) ------------------------------------------ ... 2 ... 1 ... a_stack.push(1); ... Now there are two problems: how to write a mechanism for sending messages to objects, and how to write a mutable object Q: What's your idea of what an object is like in C++? ------------------------------------------ PLAN FOR OBJECTS AND SEND Idea: object = closure = environment (data members) and methods map (fun members) methods map : message -> method So: message send = ------------------------------------------ ... extract method using method map, then call This is like the general view in semantics of OO object is record of members, message send = extract and call function member. ------------------------------------------ EXAMPLE OBJECT (define a-stack (let ((stk '())) (lambda (message) (case message ((empty?) (lambda () (null? stk))) ((push!) (lambda (x) (set! stk (cons x stk)))) (else (error "stack: Invalid message" message)))))) ------------------------------------------ ... ((pop!) (lambda () (if (null? stk) (error "Stack empty") (set! stk (cdr stk))))) ((top) (lambda () (if (null? stk) (error "Stack empty") (car stk)))) Q: What does the message send then look like with this rep of objects? ((obj msg) arg1 arg2 ...) (Can we beta-expand that? Yes!) ------------------------------------------ MESSAGE SEND (send obj msg arg1 arg2 ...) = ((obj msg) arg1 arg2 ...) (define send ;; TYPE: (-> (datum ...) datum) (lambda send-args ;; this isn't very careful (if (< (length send-args) 2) (error "send: too few args") (let ((obj (car send-args)) (msg (cadr send-args)) (args (cddr send-args))) (apply (obj msg) args))))) ------------------------------------------ Draw a picture of this, if time. We'll do this better later. Q: This gives us exactly one stack. How can we set it up to make more? make a function that returns this closure, naturally Q: (if time) can you turn this into the same for cells?