Structure inside of structure

Re-cap: Write
;; service-brand? : brand num -> bool
;; Determines whether brand needs servicing after flying given miles.
;;
(define (service-brand? a-brand miles)
  ...)

; test cases
(service-brand? (make-brand 'DC-10 550 282 15000)     5) = false
(service-brand? (make-brand 'DC-10 550 282 15000) 20000) = true
(service-brand? (make-brand 'DC-10 550 282 15000) 15000) = true
As we saw last time, we can use define to create place-holders, which save us typing; useful whenever we would use the same value twice:
; Attach a name to a particular brand, for easy re-use:
;
(define my-fave-brand (make-brand 'DC-10 550 282 15000))

; Tests:
(service-brand? my-fave-brand     5) = false
(service-brand? my-fave-brand 20000) = true
(service-brand? my-fave-brand 15000) = true


A plane (one particular plane, not a brand) consists of three pieces of information. Its brand, how many miles it has flown since its last servicing, and the name of the mechanic who last serviced it.

Write a data definition for a plane.

(define-struct plane (brand miles mechanic))

;; A plane is a structure
;;    (make-plane brand num symbol)
;; where brand is a brand structure, 
;; miles is the number of miles flown since the last overhaul, and
;; mechanic is the name of the mechanic who served you.
;;
What functions does DrScheme create when you perform the definition?
make-plane, plane-brand, plane-miles, plane-mechanic, ... and plane?.
Write examples of plane data.
(make-plane (make-brand 'DC-10 550 282 15000) 1000 'Joe)
(make-plane (make-brand 'DC-10 550 282 15000)  500 'Jane)

Okay, we are now going to write 50 functions, all processing planes. Will these 50 functions have stuff in common? Sure! If they process the same type of data, they'll all look similar. In fact, I claim we can get started already: We'll write a template for a program that processes planes.

(define (template-for-plane  a-plane ...)
   ... (plane-brand a-plane) ...
       (plane-miles a-plane) ...
       (plane-mechanic a-plane) ... )
After writing this, let's comment it out and set it aside. After all, we can cut/paste it 50 times, to save our fingers.

Write a program service-plane?:

;; service-plane? : plane --> boolean
;; Does the given plane need to be serviced?
;;
(define (service-plane? a-plane)
  ...)

; Tests:
(service-plane? (make-plane (make-brand 'DC-10 550 282 15000) 12000 'jane))
   =  ???
(service-plane? (make-plane (make-brand 'MD-80 505 141 10000) 12000 'jane))
   =  ???
(service-plane? (make-plane (make-brand 'DC-10 550 282 15000) 17003 'bubba))
   =  ???

Write a program overhaul, which takes a plane and a mechanic's name and returns a new plane with the updated servicing information.

;; overhaul : plane symbol -> plane
;; Return information for plane after servicing.
;;
(define (overhaul a-plane mech)
  ...)

; Tests:
(overhaul (make-plane (make-brand 'DC-10 550 282 15000)   500 'jane)  'bubba)
   =  (make-plane (make-brand 'DC-10 550 282 15000)   0 'bubba)
(overhaul (make-plane (make-brand 'MD-80 505 141 10000) 12000 'jane)  'jane)
   =  ???
(overhaul (make-plane (make-brand 'DC-10 550 282 15000) 17003 'bubba) 'shep)
   =  ???

Flying objects

(define-struct peach (capacity seagulls))
;;
;; A peach is a structure
;;  - (make-peach num num)
;; where capacity is the seating capacity,
;; and seagulls is the number of gulls pulling the giant peach.


(define-struct ufo (capacity planet))
;;
;; A ufo is a structure
;;  - (make-ufo num num)
;; where capacity is a number and planet is a symbol (planet of origin).


;; Data definition:
;; A flying-object is one of
;;  - a plane,
;;  - a peach, or
;;  - a ufo


;; Examples of the data, including names:
(define sky-king  (make-plane (make-brand 'DC-10 550 282 15000) 400 'amy))
(define air-james (make-peach 5 27))
(define teacup    (make-ufo 53 'planet-X))
(define voyager   (make-ufo  0 'earth))

(Can we re-use capacity as a field-name, like this? Yes, you can re-use names across structs. Remember, DrScheme incorporates the name of the struct into each function it creates behind the scenes, so there's no ambiguity. You can't define two structs with the same name though.)

Now we will write a function that processes flying-objects. We have a definition for flying-objects; I'll bet our code will look like that definition! The definition has three cases, so what will our code have? (Note that we can start to write the template, just on the knowledge that we'll handle a flying-object, even w/o knowing exactly what the function will do. That is, we can do most of our homework mechanically, w/o having to think.)

First, write code which takes in a flying-object, and asks which type of flying-object it happened to get:

;; flying-object-template : flying-object ... -> ...
;; Generic form of *any* function handling flying-objects.
;;
(define (flying-object-template a-fo)
  (cond [(plane? a-fo)       ...]
        [(peach? a-fo) ...]
        [(ufo? a-fo)         ...]))
But wait, there's more! In each of these cases, we realize that afo had further information inside of it, and we can at least remind ourselves (for each case) of what pieces of info we'll have at hand:
;; flying-object-template : flying-object ... -> ...
;; Generic form of *any* function handling flying-objects.
;;
(define (flying-object-template afo)
  (cond [(plane? afo) ..(plane-brand afo)..(plane-miles afo)..(plane-mech afo)..]
        [(peach? afo) ..(peach-capacity afo)..(peach-seagulls afo)..]
        [(ufo? afo)   ..(ufo-capacity afo)..(ufo-planet afo)..]))
What is interesting about this template? We've written most of the function, w/o even knowing what the function will do! Note that we can remind ourselves, about the type of each sub-part mentioned in the template.

Got to here sep.07 (fri); assignment: type in following example before next lect.

Let's save this template in comments, so we can cut/paste it for all future functions. ... Like:
;; more-room? : flying-object num -> boolean
;; Is there more room in the flying-object,
;; given that there are already pass-so-far people on board?
;;
(define (more-room? afo pass-so-far)
  (cond [(plane? afo)   (brand-room? (plane-brand afo) pass-so-far)]
        [(peach? afo)   (> (peach-capacity afo) pass-so-far)]
        [(ufo? afo)     (> (ufo-capacity afo) pass-so-far)]))

(more-room?  sky-king 210) = true
(more-room?  air-james  0) = true
(more-room?  air-james (peach-capacity air-james)) = false
(more-room?  voyager  0)   = false
(If, for example, the number of passengers that can fit in a giant peach also depends on how many seagulls it has, the template suggests exactly where that code should be placed.)

Will this function work? Well, of course we have yet to write brand-room?, but it's a minor leap of faith to believe we can do that. Once that function is written and works, then certainly this one should be fine. [ian: This is setup for the leap-of-faith of recursion, soon.]

;; brand-room? : brand num -> boolean
;; Determine if a brand has enough seats for a number of passengers.
;;
(define (brand-room? a-brand pass)
  (> (brand-seats a-brand) pass))

; Tests
(brand-room? (make-brand 'DC-10 550 282 15000)  281) = true
(brand-room? (make-brand 'DC-10 550 282 15000)  282) = false
(brand-room? (make-brand 'MD-80 505 141 10000)    0) = true
Note: To keep things from getting too complicated, always follow this rule:
Withing a cond line, when you have extracted the data, don't further look inside the extracted piece! E.g., (plane-brand afo) gave us a brand, but we defer the looking-inside of the brand to a different function. We'll see future problems, where this rule forces us to keep the solution clean and simple.

Summary: We've now seen several examples of using structs to model real world information. Of course, there is a difference between information (in the real world) and data (what we can give to DrScheme).

			     |
         real plane	     |       plane struct
       a human mechanic      |       mechanic name
			     |
	Information	     |		Data
			     |
A program is always modeling some problem. Models inherently mean throwing away some information, and keeping only the pertinent info (e.g., the color of a plane doesn't contribute to the info we're concerned with, so our model ignores that aspect.) Structs are essential tools in this modeling -- they let our program reflect the model (how we think about the problem).