Laboratory 2 will be collected from your GitLab repository on Thursday, April 8, 2021 at 11:59pm.

Preliminaries

We have pre-seeded your repositories with a template file named lab2.rkt in a directory called lab2. To get started, update your local repository.

cd cs151
git pull

assuming that cs151 is the name of your local repository. At this point, if you do a ls command, you should see a directory named lab2 (in addition to the include and lab1 directories).

Open the lab2.rkt file in DrRacket. Once you have opened your lab2.rkt file with DrRacket, go to the Language menu, then select "Choose Language…​", and then choose "Determine language from source" from the popup menu on the lower left edge of the application window.

You will notice that the lab2.rkt file contains the following code:

#lang typed/racket

;; CMSC15100 Spring 2021
;; Lab 2
;; <YOUR NAME HERE>

;; List your collaborators in a comment

;; include CS151-specific definitions
(require "../include/cs151-core.rkt")

;; include testing framework
(require typed/test-engine/racket-tests)

;; YOUR CODE HERE

;; run tests
;;
(test)

You should replace "<YOUR NAME HERE> with your name and the code that you write for this lab will replace the "YOUR CODE HERE" comment.

Description

This week, you will practice working with conditional expressions, function definitions, and program design by implementing some common useful operations on calendar dates.

Note that, unless otherwise specified, you may assume that function arguments are valid.

We define a formula for computing the day of the week below. The formula only works for the 20th and 21st centuries, so your dates will be restricted to that range.

First write a function is-leap-year? of type (Integer -> Boolean) to compute whether or not a year is a leap year. Leap years are not simply every fourth year. The precise rule is as follows:

A year is a leap year if it is divisible by 4 and not divisible by 100, or if it is divisible by 400.

For the time being, you do not need to account for negative years; you may assume your function is given only nonnegative arguments. Since the is-leap-year? function requires testing the divisibility of one integer by another, you should consider first writing a helper function that implements the divisibility test.

Note
TIP:

TypedRacket provides the function quotient that divides one integer by another and returns an integer result. The function remainder returns the remainder of dividing one integer by another.

Second, using the is-leap-year? function, write a function days-in-month that given a year and month (months are represented by integers from 1 to 12), returns the number of days in the month. It should have the signature

(: days-in-month : Integer Integer -> Integer)

We would like to reject dates like September 31, 2021, or, for that matter, September 32, 2021. Write a function as specified to determine whether a given year, month, day combination represents a valid date.

(: valid-date? : Integer Integer Integer -> Boolean)

The arguments are (in order) the year, month, and day. Thus, to check if March 32, 2020 is valid, we evaluate

(valid-date? 2020 3 32)

Besides checking that a calendar date exists, this function should also check that it is between the years 1900 and 2099 inclusive, and return #f if it is not.

We now give the formula for computing the days of the week. We first define a "month adjustment" as follows:

Month Adjustment

Jan

0 for leap years, 1 otherwise

Feb

3 for leap years, 4 otherwise

Mar

4

Apr

0

May

2

Jun

5

Jul

0

Aug

3

Sep

6

Oct

1

Nov

4

Dec

6

The day of the week formula is this. Let \(y\), \(m\), and \(d\), be the year, month, and day of a given date, and let \(\mathit{adj}\) be the "month adjustment" (per the table above) for the given month and year. Then let \(n\) be the following:

\[ n = (y - 1900) + \mathit{adj} + d + \lfloor\frac{y}{4}\rfloor\]

where \(\lfloor\frac{y}{4}\rfloor\) is the integer quotient of \(y\) divided by 4. (For example, \(\lfloor\frac{401}{4}\rfloor\) is 100). You should use the Typed Racket operation exact-floor to compute the \(\lfloor\cdot\rfloor\) operator in your code. Let \(w\) be the remainder of \(n\) divided by 7. Then if \(w = 0\), the day is Sunday; if \(w = 1\), the day is Monday; …​; and if \(w = 6\), the day is Saturday.

Write the function

(: day-of-week : Integer Integer Integer -> String)

which takes a date specified as year, month, and day, and returns the abbreviated name of the week day (i.e., "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", or "Sat"). You should use a helper function that computes day of the week (as described above) and a helper that maps the integer representation of a day to its string name.

For the present, assume the function is not given a bogus date, even though you have written a date verifier.

Note
TIP:

Explore the terminal command cal. When you construct tests for this function, you can use cal to check your answers. You should test at least one day from every month of the year.

Finally, write a function to generate a convenient string representation of a date.

(: date->string : Integer Integer Integer -> String)

The date string should have the following form: "Mon Oct 5, 2015". You should furthermore return the string "[invalid date]" for nonexistent or out-of-range dates. Some examples follow:

> (date->string 2000 1 1)
"Sat Jan 1, 2000"
> (date->string 1980 7 8)
"Tue Jul 8, 1980"
> (date->string 2013 10 9)
"Wed Oct 9, 2013"
> (date->string 2013 9 32)
"[invalid date]"

To implement date->string, you will need to use the Racket functions string-append and number->string. Note that string-append, like +, * and many other Racket operations, is of variable arity: it consumes 0 or more arguments. All of the arguments to string-append must be strings.

You should also write a helper function month->string to handle the conversion of month numbers to strings.

Notes

Every function must be preceded by a type signature and a purpose, and be followed by check-expect tests. Make sure to include enough tests so that you can be confident that your code does not have a bug. On these points, we do not differentiate between "helper functions" and "main functions" — all functions should have type signature, purpose comment, and tests.

Submission Instructions

The assignment must be pushed to the GitLab server by Thursday, April 8, 2021 at 11:59pm; we do not accept late work. Remember that to submit your work you will have to add and commit it to your local repository, and then push your changes to the server. You can verify that your work has been submitted by using the web interface to the server.

We strongly recommend pushing your code after you write and test each function; do not wait to the last minute to discover that you cannot commit your work for some reason!!

Also, remember to include, in comments, the names of the other students you worked with during the lab meeting.