(not (> 3 7)) = true (not (> 7 3)) = false (not true) =First let's confirm our knowledge of booleans:
;; likes-bananas? : num bool bool --> bool ;; Return true if you like bananas, according to the ;; medical guidelines in the attached handout. ;; (define (likes-bananas? potassium-today allergic? is-monkey?) ...) ;Tests: ; (likes-bananas? 1 false false) = (likes-bananas? 3 true true) = (likes-bananas? 1 true false) =
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 'grade1What 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
Write a program 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 ; (babel 'spanish) = 'hola ; (babel 'french) = 'bonjour ; (babel 'pig-latin) = 'ellohay ; (babel 'esperanto) = 'helloNote how the cond statement can have the special keyword else as its final question. It's a question that's always true. (If the language designers hadn't included that particular keyword, what could we have used instead? Why did the language designers add another word, if it's not really needed?)
Another exerccise:
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.
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:
;; 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]))
Good. Now, a related problem:
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. This follows our principle of program-mirrors-our-thinking. In Scheme, we use structures to create compound data.
What information do we want for a brand? We want its 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)) ;; ;; A Brand is: ;; (make-brand symbol num num num) ;; where 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 that we can use to create data with our new structure.
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 'DC-10 550 282 15000) (make-brand 'MD-80 505 141 10000) (make-brand 'ATR-72 300 46 5000)(One possible note of confusion: by this definition, one could create two types of DC-10s, with different capacities, etc. Perhaps "model" would a better word than "brand", to indicate it's a construction style; hopefully two companies don't make different styles but give them the same name, although this could happen in real life.)
We'll see the rest of the story about creating and using structures next time.