Get the starter code.
Due: Wednesday, October 11, 11:59pm Pacific Time
You will write 12 OCaml functions (and tests for them) related to calendar dates.
In all problems, a "date" is an OCaml value of type int * int * int
, where the
first part is the day-of-the-month, the second part is the month, and the third
part is the year. For example, (2, 10, 2023)
represents the second day of the
tenth month (October) in the year 2023.
A "reasonable" date has a positive year, a month between 1 and 12 (inclusive on both ends), and a day no greater than 31. For full credit, you only need to handle reasonable dates, but you should not explicitly check whether your input is reasonable, and your solution will naturally work correctly for some non-reasonable dates, too.
A "day of year" is a number between 1 and 365 (inclusive on both ends). For example, 33 represents February 2nd. We ignore leap years.
To access elements of a date, use the functions fst3
, snd3
, and thd3
provided in the starter code to access the first, second, and third components,
respectively. You do not need to understand how these functions are implemented;
we will study that next week.
When writing your solution, feel free to refer to the library functions listed at the end of this document.
When we ask you to write tests, you should cover all branches in the current function. For recursive functions, you should cover the case where 0, 1, and more than 1 recursive calls are made. You should also cover any boundary cases as you see fit. You should generally not test the behavior of your functions on inputs that violate assumptions that the problems tell you to make.
Write a function is_older
that takes two dates and evaluates to true or
false. It evaluates to true if the first argument is a date that comes
strictly earlier in time than the second argument. (If the two dates are the
same, the result is false.)
Write tests to convince your reader that your function is correct.
Write a function number_in_month
that takes a list of dates and a month
(i.e., an int
) and returns how many dates in the list are in the given
month.
Write tests to convince your reader that your function is correct.
Write a function number_in_months
that takes a list of dates and a list of
months (i.e., an int list
), and returns the number of dates in the list of
dates that are in any of the months in the list of months. Assume the list
of months has no duplicates.
Write tests to convince your reader that your function is correct.
Hint: Use your answer to the previous problem.
Write a function dates_in_month
that takes a list of dates and a month
(i.e., an int
) and returns a list holding the dates from the argument list
of dates that are in the month. The returned list should contain the dates
in the order they were originally given.
Write tests to convince your reader that your function is correct.
Write a function dates_in_months
that takes a list of dates and a list of
months (i.e., an int list
) and returns a list holding the dates from the
argument list of dates that are in any of the months in the list of months.
Assume the list of months has no duplicates.
Write tests to convince your reader that your function is correct.
Hint: Use your answer to the previous problem and OCaml's list-append operator.
Write a function get_nth
that takes a list of strings and a positive int
\(n\) and returns the \(n^\mathrm{th}\) element of the list where the head of
the list is \(n = 1\). (In other words, use 1-indexing, not 0-indexing!) Do
not worry about the case where the list has too few elements—your
function may apply List.hd
or List.tl
to the empty list in this case,
which is okay, and you should not check for this case explicitly.
Write tests to convince your reader that your function is correct.
Write a function string_of_date
that takes a date and returns a string
of
the form October-4-2023
(for example). Use the operator ^
for
concatenating strings and the library function string_of_int
for
converting an int
to a string
. For producing the month part, do not
use a bunch of conditionals. Instead, use a list holding 12 strings and
access it using your answer to the previous problem. For consistency, use
hyphens exactly as in the example and use capitalized English month names:
January, February, March, April, May, June, July, August, September,
October, November, December.
Write tests to convince your reader that your function is correct.
Write a function number_before_reaching_sum
that takes an int
called
\(\mathit{sum}\), which you can assume is positive, and an int list
, which
you can assume contains only positive numbers, and returns an int
. You
should return an int
\(n\) such that the first \(n\) elements of the list add
to less than \(\mathit{sum}\), but the first \(n+1\) elements of the list add to
\(\mathit{sum}\) or more. Assume the entire list adds to more than
\(\mathit{sum}\)—it is okay for an exception to occur if this assumption
is violated, and you should not check for this case explicitly.
Write tests to convince your reader that your function is correct.
Write a function what_month
that takes a day of the year (i.e., an int
between 1 and 365 inclusive on both ends) and returns an int
indicating
what month that day is in. Use a list holding 12 integers and your answer to
the previous problem. For example, if the input is 35, the output should be
2, because 35 represents February 4th, and February is the 2nd month of the
year.
Write tests to convince your reader that your function is correct.
Write a function month_range
that takes two days of the year, day1
and
day2
, and returns an int list
[m1; m2; ...; mn]
where m1
is the
month of day1
, m2
is the month of day1 + 1
, ..., and mn
is the month
of day2
. Note the result will have length day2 - day1 + 1
or length 0 if
day1 > day2
.
Write tests to convince your reader that your function is correct.
Write a function oldest
that takes a list of dates and returns an
(int*int*int) option
. It evaluates to None
if the list is empty;
otherwise, it evaluates to Some d
where d
is the oldest date in the
list. (Remember that "oldest" means "earliest in time".)
Write tests to convince your reader that your function is correct.
Hint: Use is_older
to compare dates.
Write a function cumulative_sum
that takes a list of numbers and returns a
list of the partial sums of these numbers. For example, cumulative_sum [12;
27; 13] = [12; 39; 52]
.
Write tests to convince your reader that your function is correct.
Hint: Use a helper function that takes two arguments.
There may be some problems that ask you to do something similar to a function in the standard library. Do not copy the code from the standard library, because it uses features we have not covered in class.
The sample solution is approximately 100 lines of code.
Evaluating your homework solution should generate these bindings:
val is_older : (int * int * int) * (int * int * int) -> bool
val number_in_month : (int * int * int) list * int -> int
val number_in_months : (int * int * int) list * int list -> int
val dates_in_month : (int * int * int) list * int -> (int * int * int) list
val dates_in_months : (int * int * int) list * int list -> (int * int * int) list
val get_nth : string list * int -> string
val string_of_date : int * int * int -> string
val number_before_reaching_sum : int * int list -> int
val what_month : int -> int
val month_range : int * int -> int list
val oldest : (int * int * int) list -> (int * int * int) option
val cumulative_sum : int list -> int list
Generating these bindings does not guarantee that your solutions are correct.
Include your tests in the same file as your solutions. Your tests will generate additional bindings.
Upload your code as a file called hw1.ml
to Gradescope.