Lecture 4 : Structure

Recap:

We saw last time, structures. In particular: (define-struct brand (type speed seats service)). This tells DrScheme that we have a new type of data (in addition to numbers, booleans, symbols).

What are some particular values of this type? Let's create some brands:

; Examples of the data:
;
(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.

(define-struct brand (type speed seats service))
;; A brand is a structure
;;   (make-brand symbol num num num)
;; where type is the model/make, speed is the cruising speed,
;; seats is the seating capacity, and service is the number
;; of miles before an overhaul is required.
;; type is the mode
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 new functions, behind the scenes: 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.

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

On a different note, we did a lot of typing there, repeating the construction of the DC-10 structure. Doesn't this go against the spirit of our rule, Don't Repeat Code (a.k.a. re-use existing functions/code)? Besides, what if the FAA changes its rules, requiring DC-10's to be serviced every 13000 miles, instead?

Solution: placeholders (i.e., named constants).

(define kilos-per-pound  2.2)
(define pi 3.14)
(define dollars-per-euro 0.88)
(define cutoff-grade-A   0.88)

(define my-favorite-brand (make-brand 'DC-10 550 282 15000))
(define MD-80 (make-brand 'MD-80 505 141 10000))
In this last case, what is the difference between MD-80, and 'MD-80? A big one! One is a placeholder, and the other is a symbol. Note: placeholders only help save typing, nothing more. You can always replace a place holder with its defined value -- in fact that's all drscheme does (we'll see the exact rules soon).


Note to labbies:

In lecture, students have seen a program using cond, and structures, but i have *not* yet used the term "template".

The cond example took in one of three different symbols (a model of airplane), and returned a number (the max-speed of that model). This example was *before* they saw structures.

Then, they have also seen structures -- but we revised our earlier version to make a structure "brand", which comprised a symbol (name) and a number (speed).

The hitch is that if you just say "like the airplane example", you need to be sure to emphasize:

  1. the initial attempt,
    representing brands as symbols, and having cond-based functions which held the info for each type of brand,
  2. or
  3. the revised attempt,
    representing brands as a struct, and extracting out the fields.


At home exercise:
Working for a vet clinic, we need to model pets. The clinic cares about the following: type of animal, age, has-had-shots?, chases-vets?. Follow all appropriate steps of the design recipe.
  1. make a structure for pets
  2. make some examples (perhaps giving it a name, perhaps not)
  3. write an expression that extracts whether the pet has had its shots?
  4. write a function needs-shots?, which returns true exactly when the pet is older than 1yr, and hasn't already had its shots.
  5. write a program pet-whoopie, which takes in two pets, and returns a new pet of age 0 w/o shots; the pet's type is the same as the first parameter's pet-type.
  6. write a program age-pet: it takes in a pet, and returns a pet of the same type which is a year older.
    Note: calling age-pet or pet-whoopie does not change any existing pets, no more than calling + changes the numbers it receives. These functions return new pets.


Reminder of the Design Recipe:
  1. data analaysis (how will you represent the problem?)
  2. examples of data (sample inputs)
  3. contract, purpose, header
  4. develop examples of functions (use the sample inputs)
  5. write the body.
  6. test
Note that if different problems both involve the same answer to some parts, you don't need to repeat them. (E.g., the last two programs both have the same data-representation of a pet, and the same examples of the data will suffice)