Problem set 4: Composing functions
This assignment is due on Wednesday, September 18 at 11:59pm. Submit it using Handin as assignment ps4. Corrections can be presented until Friday, October 11.
This problem set builds on the skills that we introduced in Lectures 2−6. To encourage you to review those lectures, your grade on this assignment will be capped by your grade on those lectures. You can resubmit lecture exercises at any time.
Important Note: Remember to follow the design recipe whenever you design or write a function. In particular, every type mentioned in a signature must be introduced by a data definition, except for these well-known types: Number, Image, String, Color, Boolean.
1 Preparation
In your textbook, turn to Chapter 2, Functions and Programs. Read Functions and Composing Functions.
You should also know how to use the design recipe with two kinds of data definitions, Enumerations and Intervals.
2 Year, Month and Day
You will design functions that use dates as conventionally written in English. The following data definitions will be used throughout the problem set, and more will be introduced as they are needed.
; A Year is a non-negative integer ; Examples: ; 0 ; 1789 ; 2018 ; Non-examples: ; -5000 ; "AD 2018" ; A Month is one of: ; - "January" ; - "February" ; - "March" ; - "April" ; - "May" ; - "June" ; - "July" ; - "August" ; - "September" ; - "October" ; - "November" ; - "December" ; A Day is an integer at least 1 but at most 31 ; Examples: ; 1 ; 10 ; 31 ; Non-examples: ; 32 ; "today"
Note that in general, it will be your job to create the data definitions. However, for this problem set we will provide the first steps of the design recipe, including the data definitions, so that you may focus on the subsequent steps in the design recipe.
In every problem set, clearly delimit your work for each exercise using a comment like “; Exercise 1”.
; 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")
; fall? : Month -> Boolean ; decides whether the given month is between September and November
3 calendar
; calendar : Year Month Day -> Image ; returns an image of a date on a background
; A MonthFormat is one of: ; - "long" ; - "short" ; A DateOrder is one of: ; - "MDY" ; - "DMY"
; 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")
You will find the substring function useful here. Look it up in the documentation.
; 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) ...)
You will find the built-in functions string-append and number->string useful. Look them up in the documentation.
For year-month-day->date and the other functions below, be sure to write unit tests with check-expect using the examples given (as well as any other examples you see fit to devise).
Exercise 5. Use year-month-day->date to design the calendar function, the goal of this section. You will need to choose one specific MonthFormat and one specific DateOrder that you like, as well as a background image to lay the text on. (If you are looking for some visual inspiration, do an image search online for the painter On Kawara.)
4 days-between
The goal of this section is to design a program that calculates the number of days between two dates. As above, we decompose this task into subtasks to be carried out by helper functions.
To simplify, we pretend that every year has 365 days.
; year-month-day->days : Year Month Day -> Number ; returns the number of days elapsed since January 1, 0 ; given: 0 "January" 1 expect: 0 ; given: 2017 "August" 28 expect: 736444
; month->days-in-year : Month -> Number ; returns the days elapsed in the year before the given month ; given: "January" expect: 0 ; given: "September" expect: 243
Exercise 7. Finish designing year-month-day->days. Use month->days-in-year in the definition.
; days-between : Year Month Day Year Month Day -> Number
5 time-passing
In this section, the goal is to design a program which produces a simple animation of calendar. The animation will show the days of this semester passing, using animate.
Take a moment to reflect on this problem and where the difficulty lies. In a sense, we would like to feed calendar to animate, relax and watch the show. However, calendar takes three inputs, not a single number of days.
So we cannot simply compose animate and calendar. But we can design functions which allow us to connect the two. We need to turn a number of days into a Year, into a Month, and into a Day.
; days->year : Number -> Year ; takes days since 1 Jan 0 and returns the year ; given: 364 expect: 0 ; given: 365 expect: 1 ; given: 736305 expect: 2017 ; given: (year-month-day->days 1999 "December" 31) expect: 1999
; A DaysInYear is one of: ; - an integer at least 0 but less than 31 ; - an integer at least 31 but less than 59 ; - an integer at least 59 but less than 90 ; - an integer at least 90 but less than 120 ; - an integer at least 120 but less than 151 ; - an integer at least 151 but less than 181 ; - an integer at least 181 but less than 212 ; - an integer at least 212 but less than 243 ; - an integer at least 243 but less than 273 ; - an integer at least 273 but less than 304 ; - an integer at least 304 but less than 334 ; - an integer at least 334 but less than 365 ; *Interpretation*: the number of elapsed days ; since the first day of the year ; A DaysInMonth is an integer at least 0 but less than 31 ; *Interpretation*: The number of elapsed days ; since the first day of the month
Both days->month and days->day should be defined using helpers.
; days-in-year->month : DaysInYear -> Month ; takes days since the first of the year and returns the month ; given: 0 expect: "January" ; given: 31 expect: "February" ; given: 242 expect: "August" ; days->month : Number -> Month ; takes days since 1 Jan 0 and returns the month ; given: 59 expect: "March" ; given: 364 expect: "December" ; given: 736445 expect: "August" ; given: (year-month-day->days 1999 "December" 31) expect: "December"
; days-in-year->days-in-month : DaysInYear -> DaysInMonth ; takes days since the first of the year ; and returns days since the first of the month ; given: 0 expect: 0 ; given: 59 expect: 0 ; given: 364 expect: 30 ; days->day : Number -> Day ; takes days since 1 Jan 0 and returns the day of the month ; given: 0 expect: 1 ; given: 59 expect: 1 ; given: 736324 expect: 30 ; given: (year-month-day->days 1999 "December" 31) expect: 31
Finally, we are ready to build our animation.
; first-day : Number ; The number of days elapsed on August 26, 2024 since January 1, 0 (define first-day ...)
; A SemesterDay is a number ; of days since the first day of the semester ; semester-cal : SemesterDay -> Image ; takes a number of days since the first day of the semester ; and returns a calendar image of the corresponding date (define (semester-cal t) ...)
If you pass semester-cal to animate, you should see an animation that starts on August 26, 2024 and passes through the days quickly.
The calendar pages in this animation pass rather quickly: 28 per second to be exact. Let’s slow it down. Pick how many calendar pages per second you would like to see and define this number as cal-rate.
Finally, design a function semester which takes an animation tick number and produces an image by passing a SemesterDay to semester-cal. To convert the given animation tick number to a SemesterDay, multiply by cal-rate and then quotient by 28.
Your final program should produce a running animation using semester.
Help other students by answering this ungraded question: what did you have to learn to finish this problem set that we didn’t teach? Post your answer to Discord in the #ps4 channel, or put it as a comment at the bottom of your Handin submission.
Challenge Display weekend days (Saturdays and Sundays) differently from other days (e.g., by a different color of text or background). Also, freeze the animation when it gets to the last day of the semester.
Feel free to customize your calendar further. Can it display Thanksgiving Break differently, or alert you when a problem set is due?