Lab 3: Using templates
You may submit this lab to lab3 on Handin (this is optional).
Important: Whenever you write a function in this class, follow the design recipe. You will be graded accordingly.
1 Templates
In lecture this week, we defined a data type (an enumeration, to be specific) named TrafficLight for the purpose of representing the state of a traffic light. Here it is again:
; A TrafficLight is one of: ; - "green" ; - "yellow" ; - "red"
Afterwards, we defined two different functions which processed TrafficLight: draw-traffic-light and next-traffic-light. Recall what the templates (from Step 4 of the design recipe) looked like for each function:
; draw-traffic-light : TrafficLight -> Image ; draws a picture of a traffic light in the given state (define (draw-traffic-light tl) (cond [(string=? "green" tl) ...] [(string=? "yellow" tl) ...] [(string=? "red" tl) ...])) ; next-traffic-light : TrafficLight -> TrafficLight ; returns the next TrafficLight (define (next-traffic-light tl) (cond [(string=? "green" tl) ...] [(string=? "yellow" tl) ...] [(string=? "red" tl) ...]))
Notice that after the header, they are very similar. This situation happens so often that, for the sake of convenience, we may write down a template just based on the data definition, which we can then copy and paste whenever we define a function which processes that data type.
For example, the template for processing a TrafficLight is
; process-traffic-light : TrafficLight -> ... (define (process-traffic-light tl) (cond [(string=? "green" tl) ...] [(string=? "yellow" tl) ...] [(string=? "red" tl) ...]))
Note that “process-traffic-light” here is just a place holder for an actual function name. Above we have replaced “process-traffic-light” with “draw-traffic-light” and “next-traffic-light”. The name “process-traffic-light” is not intended to be used as an actual function name. It is just the name of the template. (DrRacket understands templates: the above code runs.)
Exercise 1. Here is the data definition of a Month:
; A Month is one of: ; - "January" ; - "February" ; - "March" ; - "April" ; - "May" ; - "June" ; - "July" ; - "August" ; - "September" ; - "October" ; - "November" ; - "December"
Finish writing the template process-month:
; process-month : Month -> ... (define (process-month m) ...)
Exercise 2. Here is the definition of a MonthFormat:
; A MonthFormat is one of: ; - "long" ; - "short"
Finish writing process-month-format:
; process-month-format : MonthFormat -> ... (define (process-month-format f) ...)
Exercise 3. Here is the definition of a DateOrder:
; A DateOrder is one of: ; - "MDY" ; - "DMY"
Finish writing process-date-order:
; process-date-order : DateOrder -> ... (define (process-date-order o) ...)
2 Using process-month to design functions
Exercise 4. Finish designing the following function:
; next-month : Month -> Month ; returns the month that comes after the given one (define (next-month m) ...) (check-expect (next-month "September") "October") (check-expect (next-month "December") "January")
When you get to Step 4 of the design recipe, copy the body of process-month and paste it as the body of next-month.
Exercise 5. Finish designing the following function:
; fall? : Month -> Boolean ; decides whether the given month is between September and November
When you get to Step 4 of the design recipe, copy the body of process-month and paste it as the body of fall?.
3 Using process-month-format to design functions
; format-month : Month MonthFormat -> String ; abbreviates Month to three letters or not (define (format-month m f) ...) (check-expect (format-month "November" "long") "November") (check-expect (format-month "November" "short") "Nov")
Notice that format-month has two inputs. Both inputs are enumerations, Month and MonthFormat, which have templates, process-month and process-month-format. Which one do we use? Or do we use both?
It depends on the actual function we’re defining. For format-month, on the one hand, it is necessary to process the MonthFormat. On the other hand, it is possible to avoid processing the Month: we can view the Month as a mere String and use the substring function.
When you get to Step 4 of the design recipe, copy the body of process-month-format and paste it as the body of format-month. Then change the right-hand sides of the cond clauses of format-month’s template to include the argument m: the right-hand sides should look like (... m ...).
4 Using process-date-order to design functions
Exercise 7. Use format-month to design the following function:
; A Year is a non-negative integer ; A Day is an integer which is at least 1 but at most 31 ; year-month-day->date : Year Month Day DateOrder MonthFormat -> String ; produces a date as a string ; given: 1936 "November" 12 "MDY" "long" expect: "November 12, 1936" ; given: 1936 "November" 12 "MDY" "short" expect: "Nov 12, 1936" ; given: 1936 "November" 12 "DMY" "long" expect: "12 November 1936" ; given: 1936 "November" 12 "DMY" "short" expect: "12 Nov 1936" (define (year-month-day->date y m d o f) ...)
Use string-append and number->string.
Again, we must make a decision about which inputs to process as enumerations: the options include the Month, the DateOrder, and the MonthFormat. Note that the Month and the MonthFormat will simply be passed to format-month to produce a useful string. So it remains only to process the DateOrder.
When you get to Step 4 of the design recipe, copy the body of process-date-order and paste it as the body of year-month-day->date. Then change the right-hand sides of the cond clauses of year-month-day->date’s template to include the additional arguments: the right-hand sides should look like (... y ... m ... d ... f ...).