Homework 2 is due Monday, October 9, 2017 at 11:59pm.

Similarly to last time, you will submit your work with filename hw2.rkt in a directory called hw2. The following commands, when run from within a copy of your repository, will get you started. Note the fourth instruction, touch hw2.rkt, will create a (blank) file of that name. Also, the command cd .. goes "up" one directory from the current working directory.

$ svn update
$ svn mkdir hw2
$ cd hw2
$ touch hw2.rkt
$ svn add hw2.rkt
$ cd ..
$ svn commit hw2 -m "getting ready for homework 2"
After having done this, work in the file hw2/hw2.rkt

Unlike the last homework, we should be concerned with bogus inputs, such as a value outside of a meaningful range. The way to do this is to have a condition that checks for invalid inputs. If an invalid input is encountered, call the error function with a string that describes the problem as its sole parameter:

(error "contains-digit?: digit must be in the range 0-9")
Note that the convention is for the error message to begin with the name of the function in which the error occurred.

When you raise an error in this manner, your program will print the error message and then immediately terminate. This is generally desirable, because there is often no "safe" value to return from a function that was given invalid input, and it would be inappropriate to use a meaningless result in further computations.

But, this means that you cannot test error cases using check-expect, because the program will quit in the middle of your tests. Instead, a special form, check-error allows you to test error handling. It works similarly to check-expect: you provide a function call that, in this case, you expect to raise an error. But, instead of providing the expected result value, you provide the error string that you expect, typed exactly the same way;

(check-error (widgets-per-grommet 17 12) "widgets-per-grommet: number of widgets must be even")
the test will pass if and only if a matching error was generated. There is special machinery in the implementation of check-error that allows it to continue with the next test, rather than terminating your program prematurely.

Preliminaries

(Same as last week.)

At the top of your hw2.rkt file, write this line to designate Typed Racket as the current language:

#lang typed/racket

Then, add the following lines:

(require typed/test-engine/racket-tests)
(require "../include/cs151-core.rkt")

At the bottom of the file, call the test function (with no arguments) to run the check tests:

(test)
This function call — (test) — should remain as the last line of your program even as you are working on the code above it.

Homework Problems

For every function you write, you must preface the function definition with a type ascription (also known as a contract) and a purpose, and you must follow it with tests with check testers (check-expect, check-within, etc.). Do write helper functions where it seems like a good idea to do so. All functions need contracts, purposes and tests, even if they are "only" helper functions. (In actuality, a function is just a function, and the "helper function" designation is an illusion.) You may also call functions from other functions whenever you like.

Problem 1

Singular Wireless charges for monthly mobile broadband usage on a smartphone as follows: The first 300 MB of data costs $20. If a customer uses between 300 MB and 3 GB (3072 MB) of data, he or she pays $30 in total. If a customer exceeds 3 GB, he or she pays an overage of $15 per GB (1024 MB) above and beyond the 3 GB level. When a customer incurs an overage, he or she is given buckets of extra data, 1 GB at a time, at the $15 rate; overages are not pro-rated by smaller increments.

Write the function mobile-broadband-cost, which consumes the (integer) number of megabytes a customer has used in a month, and returns the dollar amount to bill that customer according to the rules above.

Problem 2

In this problem, you will write functions that examine the individual digits of an Integer. For instance, the number 122333 is both a number over one hundred thousand, and a number comprised of six digits: one 1, two 2s, and three 3s when viewed as a decimal number.

We can use basic mathematical operations to access the individual digits of any such number, by exploiting how the place-value system (also known as "positional notation") works: think about how to get the digit in the ones place, and how to get the set of digits that result from "chopping off" the ones place using simple operations.

If we want to investigate a property of the digits of an arbitrary number, we would need to examine the digits in turn, but we cannot anticipate how many there are in advance. Recursion gives us the ability to scan down the digits, however many there may be.

We need to be precise about how to handle zeros in the decimal representation of a number. For instance, the number 15100 has two zeros. But the exact same number can be written as 015100 -- this has the same mathematical value, but appears to have three zeros. These so-called "leading zeros" do not change the value of the number, and we can have arbitrarily many of them, confusing the issue of counting the number of zeros in a number. For this problem, we will never attempt to count leading zeros.

On a related note, consider the number 0 itself. We write a single digit, the digit 0, when we write this number. But it serves almost as a placeholder to show that there is a number being written; arguably this digit is itself a leading zero in front of a blank number. So, we will consider the number 0 to have no digits at all, for the purposes of this problem.

Write the following functions:

Problem 3

The eyeWatch is a new smartwatch that, among other things, tracks your activity throughout the day. To entice you to be more active, it displays three pie charts indicating, respectively, for how many minutes you were standing throughout the day, how many calories you burned during exercise throughout the day, and for how many minutes you had an elevated heart rate throughout the day (indicating aerobic exercise).

In your hw2.rkt file, define a struct named Activity with three fields, each an Integer, in the following order: one named mins-standing, one named cals-burned, and one named mins-elev-hr.

Then, implement the following functions to work with this data:

Problem 4

Last time, we wrote a function, eval-quadratic, to calculate the y-value of a quadratic function at a given x-value. It took four parameters; the first three were the three coefficients of a quadratic equation.

This was a bit unwieldy; it would be better to bundle together these three values into a single data structure. So, let's do that with the following struct definition:

(define-struct Quadratic
  ([a : Real]
   [b : Real]
   [c : Real]))

Copy and paste the above definition into your hw2.rkt file, and then implement the following functions over Quadratics:

Submit Your Work

Submit your work by committing hw2/hw2.rkt to your CS151 subversion repository by Monday, October 9 at 11:59pm. All your work must be contained in that one file.

You should commit your work early and often. Intermediate commits — that is, commits made along the way to the final commit — are strongly encouraged; only your last commit before the deadline will be evaluated by your graders.

A note on style. Please make sure your lines of code are not more than 80 characters long. You can see the current character number at the bottom center of the DrRacket window. Use line breaks to clarify your code, and press TAB frequently within DrRacket to align the code correctly.