Lecture 4 : Adding Some Structure

JetSet airlines has three kinds of planes in its fleet: DC-10's, which
carry 282 people and have a max speed of 550 mph, MD-80's, which carry
141 people and have a max speed of 505 mph, and ATR-72's, which carry
46 people and have a max speed of 300 mph.  

Write a program capacity which takes a brand and returns the number
of people that the brand can carry.

; capacity : sym -> num
; return the capacity of a plane
(define (capacity brand-name)
  (cond [(symbol=? brand-name 'DC-10) 282]
        [(symbol=? brand-name 'MD-80) 141]
        [(symbol=? brand-name 'ATR-72) 46]))

Write a program max-dist which takes a plane brand and a number of
hours and returns the max distance that that plane can travel in the
given number of hours.

; max-dist : sym num -> num
; calculate the max distance that a brand can travel in given hours
(define (max-dist brand-name hours)
  (cond [(symbol=? brand-name 'DC-10) (* 550 hours)]
        [(symbol=? brand-name 'MD-80) (* 505 hours)]
        [(symbol=? brand-name 'ATR-72) (* 300 hours)]))

What do you notice about these two programs?  They have a very similar
structure (only the program name and the answers in each cond clause
are different).  This is an example of how a program's structure
follows from the problem structure.

Is anything unsatisfying about this?  Yes, information about a brand
is scattered among these functions.  Ideally, we should be able to
keep all information about one brand together.  In other words, we
want to treat all of these pieces of information as one compound piece
of information.  In Scheme, we use structures to create compound data.

What information do we want for a brand? type, speed, seats, and how
many miles it can fly before requiring servicing.  In Scheme, we would
write

	(define-struct brand (type speed seats service))

Define-struct tells DrScheme "I need a new kind of information".
Define-struct takes a name for the new kind of information and a list
of names for the pieces of information that we want to glue together.
This is called compound data.  Evaluating it tells DrScheme that we
want the ability to create data with the given name and number of
fields.  Accordingly, DrScheme defines an operator that we can use to
create data with our new structure.

Let's create some brands:  (make-brand 'DC-10 550 282 15000)
                           (make-brand 'MD-80 505 141 10000)
                           (make-brand 'ATR-72 300 46 5000)

When we define compound data, we need to document what kinds of
information are in that form of data.  We call this documentation a
data definition.  Here's the data definition for a brand.

;; A brand is a structure
;;   (make-brand type speed seats service)
;; where type is a symbol and speed, seats, and service are numbers

You must write a data definition every time you use define-struct.

Let's rewrite our max-dist function so that the input is now a brand
structure, rather than a brand name.  Note that we now need a way to
access information inside the structure.  When we evaluated the
define-struct, DrScheme also created these accessor functions for us.

;; max-dist : brand num -> num
;; compute the maximum distance that a brand can fly in a given number
;; of hours
(define (max-dist a-brand hours)
  (* (brand-speed a-brand) hours))

;; Examples
(max-dist (make-brand 'DC-10 550 282 15000) 2) = 1100

Summary: When DrScheme evaluates 
	(define-struct brand (type speed seats service))
it creates five operators: make-brand
                           brand-type 
                           brand-speed
                           brand-seats
                           brand-service

Try another.  Write a program needs-service? which consumes a brand
and a number of miles and returns true if the brand must be serviced
having flown the given number of miles.

1. Data Analysis
2. contract, purpose, header
3. Examples
4. Template
5. Body
6. Test

;; needs-service? : brand num -> bool
;; determines whether brand needs servicing after flying given miles
(define (needs-service? a-brand miles)
  (>= miles (brand-service a-brand)))

; test cases
(needs-service? (make-brand 'DC-10 550 282 15000) 5) = false
(needs-service? (make-brand 'DC-10 550 282 15000) 20000) = true
(needs-service? (make-brand 'DC-10 550 282 15000) 15000) = true