Let's recap. The previous lecture studied set-structure!. We can reason about set-structure! the same way that we reason about set!: by erasing and replacing values used when a structure was created. However, structure updates can take effect across function calls and we have to be careful about sharing them. Recall the add-child-name! program that we wrote in the last class. ;; A person is a structure ;; (make-person N F M C) ;; where N is a symbol, ;; F and M are person or false, and ;; C is (listof person) (define-struct person (name father mother children)) ;; add-child-name! : symbol person person -> person ;; creates a node for a child, adds it to the tree, and returns the new node ;; effect : adds a new child node to the list of children in father and mother (define (add-child-name! name father mother) (local [(define child-node (make-person name father mother empty))] (set-person-children! father (cons child-node (person-children father))) (set-person-children! mother (cons child-node (person-children mother))) child-node)) Could we have written this program without using set-structure!? No, because the child and the father each need to refer to each other, and we have to create one of them first (same for mother). Could we have also written the program as follows? (define (add-child-name! name father mother) (set-person-children! father (cons (make-person name father mother empty) (person-children father))) (set-person-children! mother (cons (make-person name father mother empty) (person-children mother))) (first (person-children mother))) Let's try it out. > (define bob (make-person 'bob false false empty)) > (define ann (make-person 'ann false false empty)) > (define susan (add-child-name! 'susan bob ann)) > susan (shared ((-0- (make-person 'susan -1- -4- empty)) (-1- (make-person 'bob false false (list (make-person 'susan -1- -4- empty)))) (-4- (make-person 'ann false false (list -0-)))) -0-) > (define tom (make-person 'tom false false empty)) > (add-child-name! 'liz susan tom) (shared ((-0- (make-person 'liz -1- -9- empty)) (-1- (make-person 'susan -2- -5- (list (make-person 'liz -1- -9- empty)))) (-2- (make-person 'bob false false (list (make-person 'susan -2- -5- empty)))) (-5- (make-person 'ann false false (list -1-))) (-9- (make-person 'tom false false (list -0-)))) -0-) Do you see the problem here? We have two different nodes for susan in the tree. One (-1-) shows a child named liz. The other (inside the record for bob) shows no such child. This is clearly a problem. Once you write programs that changes values in structures, you must be very careful to share structures exactly when necessary for your program. This is a case where not sharing causes a problem. There are other cases where unexpected sharing is a problem. We've now seen two ways to update a structure: we can create a new structure, or we can use set-structure!. How do we choose between these methods? As a general rule, update a structure only if the structure represents a persistent object and your program corresponds to a real action. For example, address books are persistent objects and updates to address books represent permanent changes that we wish to make. In contrast, imagine that you were writing a program to play chess and you wanted to see what would happen if you took a particular move. You should not use a set-structure! to change the move because you haven't yet decided to take that move (it's a preliminary, not a real, action). In the last class, there was a question regarding how to alter the contents of a list. As we showed early in the course, we can think of a list as a structure containing two fields, a first and a rest. Therefore, we should be able to change the first and rest components of a list using something similar to set-structure! The operators that you need are called set-car! (to change the first) and set-cdr! (to change the rest). Here are some examples: > (define lst (list 1 2 3 4)) > lst (list 1 2 3 4) > (set-car! lst 5) > lst (list 5 2 3 4) > (set-car! (rest lst) 7) > lst (list 5 7 3 4) > (set-cdr! lst empty) > lst (list 5) > (set-cdr! lst 3) set-cdr!: second argument must be of type, given (list 5) and 3 set-car! and set-cdr! are like set-structure! in that they have effect across function boundaries: > (define (f lst) (set-car! lst 5)) > (define l1 (list 1 2 3 4)) > l1 (list 1 2 3 4) > (f l1) > l1 (list 5 2 3 4) Studying the effects of set! and set-structure! (which includes set-car! and set-cdr!) leads us to ask an interesting question: when are two structures or two lists the same? Consider the following two structures: (make-entry 'kathi 3) (make-entry 'kathi 3) Are these two structures the same? It depends on what we mean by "the same". Certainly, they have the same contents; in one sense therefore, they are the same. But are they the same structure? Let's ask DrScheme. Scheme provides an operator eq? to test whether two arbitrary values are the same: > (eq? 4 4) true > (eq? 'a 'a) true > (eq? 'a 'A) false > (eq? 4 'a) false Thus, eq? is more general than either = or symbol=?, which require their arguments to be of the appropriate type. > (define-struct entry (name phone)) > (eq? (make-entry 'kathi 3) (make-entry 'kathi 3)) false Thus, DrScheme says that (make-entry 'kathi 3) and (make-entry 'kathi 3) are not the same values. Is there a way to ask DrScheme whether two structures have the same contents? Yes, it's called equal? > (equal? (make-entry 'kathi 3) (make-entry 'kathi 3)) true Intuitively, the difference between eq? and equal? is that eq? asks whether two values were created at the same time and equal? asks whether two values have the same structure. Here are some more examples: > (eq? (list 1 2) (list 1 2)) false > (equal? (list 1 2) (list 1 2)) true > (equal? (list 1 2) (list 2 1)) false > (define-struct entry (name phone)) > (equal? (list (make-entry 'kathi 3)) (list (make-entry 'kathi 3))) true Unfortunately, our current distinction between eq? and equal? relies on intuition. In order to explain this difference more precisely, we have to get under the hood a bit to see how Scheme manages variables and structured values. We'll return to this point on Friday.