;; future_val: num, num, num -> num
;; Calculates the future value in dollars of an investment given
;; a principal in dollars, an interest rate per time period and
;; the number of periods to measured across.(define (future_val p rate nper)
(* p (expt (+ 1 rate) nper)))
(= 110 (future_val 100 .1 1))
(= 100 (future_val 100 .321 0))
(= 57.963703715 (future_val 50 .03 5))
Class exercise: write the contract, purpose and header for a function to get a stock quote for a given day.
Class exercise: write test code for your stock quote function.
In the above exercise, we wanted our function to take a stock symbol as an input. How do we represent such symbols in Scheme? What if we wanted something even more complicated, say some conglomeration of pieces of data?
(Thanks Ian, for the following discussion.)
We started with numbers as the only data type, and enriched our world (slightly) with booleans (only two of 'em -- way easier than numbers :-) Let's expand our world some more. Often, we want to compute over data other than numbers. People who study language processing, for example, need a way to represent words. In Scheme, we represent words using symbols. A symbol resembles a word, but has a quote mark on the front and can contain characters other than letters (but no spaces):
'justice 'bubbles 'blue 'chemical-X 'grade1
What operations can we perform on symbols? Does (+ 'bubbles 3) make sense? No, because 'bubbles isn't a number. The only thing we can do with symbols is compare them for equality. We do this using an operator called symbol=?:
(symbol=? 'bubbles 'bubbles) = true
(symbol=? 'bubbles 'blue) = false
Let's write a program called babel that takes the name of a language and produces the word for hello in that language if the language is spanish, french, or pig-latin. The program produces 'hello for any other language. (First recite: What are the four steps?)
;; babel : symbol -> symbol
;; translate hello into the given language
(define (babel lang)(cond
[(symbol=? lang 'spanish) 'hola]
[(symbol=? lang 'french) 'bonjour]
[(symbol=? lang 'pig-latin) 'ellohay]
[else 'hello]));; test-cases
(symbol=? 'hola (babel 'spanish))
(symbol=? 'bonjour (babel 'french))
(symbol=? 'ellohay (babel 'pig-latin))
(symbol=? 'hello (babel 'esperanto))
JetSet airlines has three kinds of planes in its fleet:
Let's write a program capacity which takes a brand and returns the number of people that the brand can carry.
When we start writing the contract, we suddenly wonder, how to represent the various names of airplane brands. Hmmmm, boolean won't work. I suppose we could try numbers, and then keep in our own mind "hmmm, brand#1 is a DC-10, brand#2 is ...". That certainly doesn't reflect our thinking! Symbols are a natural way to represent the brand names:
So far, so good.
;; capacity : sym -> num
;; Return the capacity of a plane
;; given it's brand.
;;
(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.
Beep! Beep! Beep! Backing up! Remember the First Law of Programming?
Do the above programs truly reflect the way that we think about airplane brands? Notice how the information about each brand is scattered through the different functions.
If you were going to buy a Toyota car, how many stores do you need to go to get all the parts? Why?
Encapsulation! -- we'rrrrrrrre baaaaack!
How can we encapsulate the information about a brand?
An encapsulation of multiple data types into a single data type is called a "structure" or "struct" for short.
What would we encapsulate into a brand?
Is there any notion of ordering to these attributes (also called fields)?
In Scheme, we write
(define-struct brand (manufacturer speed seats service))
;; A brand is:
;; (make-brand symbol num num num)
;;where manufacturer is the maker of the brand,
;; seats is the seating capacity, and service is the number
;; of miles before an overhaul is required.
.The 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. We are expanding Scheme, adding new concepts to the language!
Accordingly, DrScheme defines an operator, make-brand that we can use to create data with our new structure. This is called a constructor for the structure and is used to create a specific brand with specific values for each attribute.
So far, we have just told DrScheme that there's a new type of data in town. Now, let's actually create some brands:
(make-brand 'Boeing 550 282 15000) ; DC-10
(make-brand 'Boeing 505 141 10000) ; MD-80
(make-brand 'Aerospatiale 300 46 5000) ;ATR-72
I put the brand name in comments above, but is it really necessary to associate the brand name with the actual brand? Or is the brand name just a convenience?
How do we get the stored information in the fields out again? Scheme also automatically creates accessor functions:
(symbol=? 'Boeing (brand-manufacturer (make-brand 'Boeing 550 282 15000)))
(= 505 (brand-speed (make-brand 'Boeing 505 141 10000)))
(= 46 (brand-seats (make-brand 'Aerospatiale 300 46 5000)))
To define a new structure:
(define-struct struct_name (attr1_name attr2_name attr3_name ...))
Automatically generated:
(make-struct_name attr1_val attr2_val attr3_val ...) --> struct
(struct_name-attr1_name struct) --> attr1_val
(struct_name-attr2_name struct) --> attr2_val
(struct_name-attr3_name struct) --> attr3_val
etc.
Don't confuse when something is a name and when something is a value!
©2002 Stephen Wong