In the last lecture, we discussed how to update an entry in an address
book: 

(define (update-address name num)
  (local [(define updated-book
		(map (lambda (entry)
		       (cond [(symbol=? (entry-name entry) name)
			      (make-entry name num)]
			     [else entry]))
		     address-book))]
	     (set! address-book updated-book)))

This solution creates a new list of entries every time update is
called.  Always creating these new lists seems unnecessary.  Ideally,
we would like a way to just change the number stored in the entry that
is already in the list, without creating a new list or a new entry.

DrScheme provides operators for changing the values stored in
structures.  When you type (define-struct entry (name phone)),
DrScheme defines two operators:

set-entry-name! : entry symbol -> void
set-entry-phone! : entry number -> void

These operators allow you to change the values stored in an entry.
As an example, consider the following sequence of interactions:

> (define-struct entry (name phone))
> (define e1 (make-entry 'kathi 3))
> e1
(make-entry 'kathi 3)
> (set-entry-phone! e1 5)
> e1
(make-entry 'kathi 5)

These operators, which we will call set-structure!, resemble set! in
that once you change a value using set-structure!, you can no longer
access the previous value.  The same cautions about using
set-structure! carefully therefore still apply.

We can view how DrScheme evaluates a set-structure! in a similar
fashion to how it evaluates set!.  When we call set-entry-phone! in
the above example, it is as if DrScheme goes back to the original
(make-entry ...) and changes the value in the structure.  Thus, if we
have

  (define-struct entry (name phone))
  (define e1 (make-entry 'kathi 3))

and we write

  (set-entry-phone! e1 5),

it is as if we had originally written

  (define-struct entry (name phone))
  (define e1 (make-entry 'kathi 5))

for the remainder of the computation.

The set-structure! operators and set! are not exactly the same
though.  Consider the following program:

(define (update-entry! entry new-phone)
  (set-entry-phone! entry new-phone))

> (define e1 (make-entry 'kathi 3))
> e1
(make-entry 'kathi 3)
> (update-entry! e1 5)
> e1
(make-entry 'kathi 5)

Notice that, unlike set!, structure-set! can affect the values of its
parameters.  Why is that?  The difference lies in the nature of the
two parameters.  Recall the swap program that we tried to write in the
last class:

(define (swap x y)
  (local [(define tmp x)]
    (set! x y)
    (set! y tmp)))

We said that calling (swap u v) would leave the values of u and v
unchanged.  This is because we tried to change the values of the
parameter, rather than values stored inside the argument passed to the
parameter.  Had we written

(define (update-entry2! entry new-phone)
  (set! entry (make-entry (entry-name entry)) new-phone))

then update-entry2! would not affect the value of an entry:

> (define e1 (make-entry 'kathi 3))
> e1
(make-entry 'kathi 3)
> (update-entry2! e1 5)
> e1
(make-entry 'kathi 3)

Thus, structure-set! can have affects that we could not achieve with
set!.  For example, we could write a program to swap two numbers
inside of a structure:

(define-struct coords (x y))

(define (swap-coords a-coord)
  (local [(define tmp (coords-x a-coord))]
    (set-coords-x! (coords-y a-coord))
    (set-coords-y! tmp)))

Using structure-set!, how could we now write the update-address-book
program?

;; update-address-book! : symbol number -> void
;; effect: changes the phone number stored with the given name in address book
(define (update-address-book! name new-num)
  (local [(define (helper! a-book)
	    (cond [(empty? helper) void]
		  [else
		   (cond [(symbol=? name (entry-name (first a-book)))
			  (set-entry-phone! (first a-book) new-num)]
			 [else (helper! (rest a-book))])]))]
    (helper! address-book)))

> (define address-book (list (make-entry 'kathi 3)))
> address-book
(list (make-entry 'kathi 3))
> (update-address-book! 'kathi 5)
> address-book
(list (make-entry 'kathi 5))

Note that our new update-address-book! does not use set!.  Why not?
Doesn't it need to set! address-book as we did in the previous version
of this program?  No.  We changed the value inside an existing entry.
That change also affects the contents of the list, so we didn't need
to use set! explicitly.  Let's study this through some examples:

> (define e1 (make-entry 'kathi 3))
> (define address-book (list e1))
> address-book
(list (make-entry 'kathi 3))
> (set-entry-phone! e1 5)
> e1
(make-entry 'kathi 5)
> address-book
(list (make-entry 'kathi 5))

When DrScheme evaluates (set-entry-phone! e1 5), it's as if we had written

> (define e1 (make-entry 'kathi 5))
> (define address-book (list e1))

so the phone number inside e1 gets changed, which affects the contents
of address-book.  That we gave the entry the name e1 is irrelevant
here.  We could have written:

> (define address-book (list (make-entry 'kathi 3)))
> address-book
(list (make-entry 'kathi 3))
> (set-entry-phone! (first address-book) 5)
> address-book
(list (make-entry 'kathi 5))

Moral: you need to be careful when using set-structure! because
changes persist beyond program boundaries.  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).

Could we also write update-address-book! using map, filter, or fold?  We
can't use map or filter because they return lists.  We could, however, use
fold as follows:

(define (update-address-book! name new-num)
  (foldr (lambda (an-entry result-rest)
	   (cond [(symbol=? name (entry-name an-entry))
		  (set-entry-phone! an-entry new-num)]
		 [else void]))
	 void address-book))

update-address-book! shows a special case of foldr, one where we want to
perform an operation on each element of a list, but we don't want to return
a value.  Scheme has another built-in abstract function for this purpose,
called for-each.  For-each consumes a function of one argument and a list.
It applies the function to each element of the list and returns void: i.e.,

(for-each f (list e1 ... en)) = (begin (f e1)
				       ...
				       (f en)
				       void)

Using for-each, we could write update-address-book! as follows:

(define (update-address-book! name new-num)
  (for-each (lambda (an-entry)
	      (cond [(symbol=? name (entry-name an-entry))
		     (set-entry-phone! an-entry new-num)]
		    [else void]))
            address-book))

We've seen one example of set-structure!: updating phone books.  Let's
consider another example.  In our previous discussion of family trees,
we looked at ancestor trees and descendent trees.  A real world
genealogical database would need trees that could be explored in
either direction.  Let's define such trees.  We must start with a data
definition for a node, or person, in the tree.  This data definition
can't be biased towards ancestors or descendents.

;; 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))

Let's write a program add-child-name!, which consumes a name, the
person structure representing the child's father, and the person
structure representing the child's mother.  The program should return
the new node for the child.

;; 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))