;; The first three lines of this file were inserted by DrScheme. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-beginner-abbr-reader.ss" "lang")((modname lect05a) (read-case-sensitive #t) (teachpacks ((lib "world.ss" "teachpack" "htdp"))) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ((lib "world.ss" "teachpack" "htdp"))))) ; Data Def'n: ; An AncestorTree is: ; - 'unknown or ; - (make-child string num symbol AncestorTree AncestorTree) (define-struct child (name year eye ma pa)) ; Examples of data: ;'unknown ;(make-child "Herman" 1893 'blue 'unknown 'unknown) ;(make-child "Shirley" ; 1913 ; 'brown ; 'unkown ; (make-child "Herman" 1893 'blue 'unknown 'unknown)) (define abe (make-child "Abe" 1920 'blue 'unknown 'unknown)) (define mona (make-child "Mona" 1929 'brown 'unknown 'unknown)) #;(make-child "homer" 1955 'brown (make-child "Mona" 1929 'brown 'unknown 'unknown) (make-child "Abe" 1920 'blue 'unknown 'unknown)) (define jackie (make-child "Jackie" 1926 'brown 'unknown 'unknown)) (define marge (make-child "Marge" 1956 'blue jackie 'unknown)) (define homer (make-child "Homer" 1955 'brown mona abe)) (define bart (make-child "Bart" 1979 'brown marge homer)) ;(define (fun-for-anc-tree an-at) ; (cond [(symbol? an-at) ...] ; [(child? an-at) (child-name an-at) ... ; (child-year an-at) ... ; (child-eye an-at) ... ; (fun-for-anc-tree (child-ma an-at)) ... ; (fun-for-anc-tree (child-pa an-at)) ... ; ])) ; size : AncestorTree -> number (define (size an-at) (cond [(symbol? an-at) 0] [(child? an-at) (+ (size (child-ma an-at)) (size (child-pa an-at)) 1)])) ;(check-expect (size 'unknown) 0) ;(check-expect (size mona) 1) ;(check-expect (size homer) 3) (check-expect (size bart) 6) ; contains-name? : AncestorTree String -> boolean (define (contains-name? an-at a-name) (cond [(symbol? an-at) false] [(child? an-at) (or (string=? (child-name an-at) a-name) (contains-name? (child-ma an-at) a-name) (contains-name? (child-pa an-at) a-name))])) (check-expect (contains-name? 'unknown "george") false) (check-expect (contains-name? bart "george") false) (check-expect (contains-name? bart "Abe") true) (check-expect (contains-name? bart "Homer") true) (check-expect (contains-name? bart "Bart") true) #| Possible next exercises: count-oldies : AncestorTree number -> number find-blue-eyes : AncestorTree -> (list-of String) find-blue-eyed-orphans find-oldies .... generalized find! find-long-names find-named-for-ancestor find-time-travelers: somebody whose has an ancestor whose birth-year is later than their own! |# ; count-oldies: AncestorTree -> number ; (define (count-oldies an-at) (cond [(symbol? an-at) 0] [(child? an-at) (+ (count-oldies (child-ma an-at)) (count-oldies (child-pa an-at)) (if (< (child-year an-at) 1988) 1 0))])) ;; find-in-tree: AncestorTree (child -> boolean) -> (list-of string) ;; Return a list of all names of child structs who satisfy 'good?' ; ; Note how this separates the tree-processing from the task of ; determining if one particular child should be included in the list. ; Just like 'filter' and like for-loops, it's a win-win to separate ; the control logic from the task. ; (define (find-in-tree an-at good?) (cond [(symbol? an-at) empty] [(child? an-at) (append (find-in-tree (child-ma an-at)) (find-in-tree (child-pa an-at)) (if (good? an-at) (list (child-name an-at)) empty))])) ; Find the names of all people in an-at who have blue eyes. ; (define (is-blue-eyed? ch) (symbol=? (child-eye ch) 'blue)) (define (find-blue-eyes an-at) (find-in-tree an-at is-blue-eyed?)) ; This is easy, now that we generalized 'find-in-tree'. ; And, find-in-tree is easier than it was when the blue-eye-checking ; was embedded inside of it. (check-expect (find-blue-eyes 'unknown) empty) (check-expect (find-blue-eyes abe) '("Abe")) (check-expect (find-blue-eyes mona) empty) (check-expect (find-blue-eyes bart) '("Marge" "Abe")) ; find-oldies: AncestorTree -> (list-of string) ; Find the names of everybody in an-at who is over 21. ; ; This is an example of how lambda gets used: ; there's no real need to give a name to the helper-function. ; Similarly we could get rid of 'is-blue-eyed?'. ; (Does defining the function in-line make the code cleaner ; or messier?, in your opinion.) ; (define (find-oldies an-at) (find-in-tree an-at (lambda (ch) (< (child-year ch) 1988))))