Now that you know how to write recursive programs, you have the
foundations needed to start writing interesting programs.  Going to
start today by studying family trees.

 -----------------|
|                 V
|   --> Susan  ->Tom    
|  /   ^     ^ |   ^
| /   /  /----\-  /   
Pat   Mike    Ann      Joe
                ^      ^
                 \    /
                  Mary


This family tree starts at the child and indicates who a person's
parents are.  What would be a good data definition for such a family
tree?  Note that this is where CS starts to get creative: in how to
design representations of information.

A ft is either
  - a symbol, or
  - (make-node name father mother)
    where name is a symbol and father and mother are ft.

(define-struct node (name father mother))

What's are examples of fts?

'Mary
(make-node 'Ann 'Susan 'Tom)
(make-node 'Mary (make-node 'Ann 'Susan 'Tom) 'Joe)

What would a template look like here?

(define (ft-func a-ft)
  (cond [(symbol? a-ft) ...]
        [(node? a-ft) ...
           (node-name a-ft) ...
           (ft-func (node-father a-ft)) ...
           (ft-func (node-mother a-ft)) ... ]))

Write the program in-family?, which consumes an ft and a symbol and
produces a boolean indicating whether a person with that name is in
the tree.

;; compare-names : sym sym -> bool
;; determine whether two names are the same
(define (compare-names name1 name2)
  (symbol=? name1 name2))

;; in-family? : ft sym -> bool
;; determine whether a person appears in a family tree
(define (in-family? a-ft name)
  (cond [(symbol? a-ft) (compare-names a-ft name)]
        [(node? a-ft) 
         (or (compare-names (node-name a-ft) name)
             (in-family? (node-father a-ft) name)
             (in-family? (node-mother a-ft) name))]))

This model of family trees is pretty simple because it only includes
people's names.  Let's make two changes to the model.  First, we want
to record additional information, such as each person's year of birth
and eye-color.  Second, we want to be able to leave either parent
unspecified (since we don't always have information about both
parents).  How would we revise the data definition?  The main
difference between the previous definition and this one is that the
nodes are now more complicated.

A ftn (for family tree node) is either
  - empty, or
  - (make-child na f m yr ec)
    where na is a sym, f and m are ftn, yr is a num and ec is a sym

(define-struct child (name father mother year eye-color))

What are some examples of this style of family tree?

empty
(make-child 'Mary 
            (make-child 'Ann empty empty 1950 'blue) 
            empty 1975 'green)

What does the template look like?

(define (ftn-func a-ftn)
  (cond [(empty? a-ftn) ...]
        [(child? a-ftn) ...
           (child-name a-ftn) ...
           (ftn-func (child-father a-ftn)) ...
           (ftn-func (child-mother a-ftn)) ...
           (child-year a-ftn) ...
           (child-eye-color a-ftn) ... ]))

What does the in-family? program look like on this data definition?

;; in-family? : ft sym -> bool
;; determine whether a person appears in a family tree
(define (in-family? a-ftn name)
  (cond [(empty? a-ftn) false]
        [(child? a-ftn) 
           (or (compare-names (child-name a-ftn) name)
	       (in-family? (child-father a-ftn) name)
               (in-family? (child-mother a-ftn) name))]))

Write the program count-female-ancestors (a person does not count as
his/her own ancestor).

;; cfa : ftn -> num
;; count how many female ancestors are in the tree
(define (cfa a-ftn)
  (cond [(empty? a-ftn) 0]
        [else (cond [(empty? (child-mother a-ftn))
                     (cfa (child-father a-ftn))]
                    [else (+ 1 (cfa (child-mother a-ftn))
			     (cfa (child-father a-ftn)))])]))

Anything wrong with this program?  Yes.  It violates our rule of
opening only one data definition per program.  This one looks at the
cases in the mother sub-tree.  Therefore, we should use a helper
function, as follows.

;; count-mother : ftn -> num
;; determines how many ancestors to add based on ftn
(define (count-mother a-ftn)
  (cond [(empty? a-ftn) 0]
	[else 1]))

;; cfa : ftn -> num
;; count how many female ancestors are in the tree
(define (cfa a-ftn)
  (cond [(empty? a0ftn) 0]
	[else (+ (count-mother (child-mother a-ftn))
		 (cfa (child-mother a-ftn))
		 (cfa (child-father a-ftn)))]))

What if we wanted to count only blue-eyed female ancestors?  What in
the above program changes?  Only the helper function, which would
change as follows:

;; count-if-blue-eyes : child -> num
;; returns 1 if node has blue eyes, else 0
(define (count-if-blue-eyes a-child)
  (cond [(symbol=? 'blue (child-eye-color a-child)) 1]
        [else 0]))

;; count-mother : ftn -> num
;; determines how many blue-eyed ancestors to add based on ftn
(define (count-mother a-ftn)
  (cond [(empty? a-ftn) 0]
	[else (count-if-blue-eyes a-ftn)]))