;; The first three lines of this file were inserted by DrRacket. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-beginner-reader.ss" "lang")((modname task-week02-planned-grad) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) #| NOTE: Don't copy/paste this file into an open DrRacket window; instead download/save the file, and then choose "File > Open..." 1. What is the signature of `string?`? Of `string=?` 2. What function can be used to tell if something is an integer? A natural-number (an integer >= 0)? 3. Task: "Class of ____" Suppose we are part of a team working on the registrar's computer system. We have been tasked with dealing with a student's "expected graduation year". (E.g. "class of 2017" -- we'll ignore semester/month.) We'll use the name `planned-grad` for this type. a. What type should we use, to represent a planned-grad? An int seems reasonable, except that we need to deal with the following four situations: - students with an expected graduation-date in the future (the most common situation). - students who have already graduated (in which case their expected-year is automatically the same as their graduation-year). - students who entered an expected graduation-date, but this date has slipped into the past (we will still want to know their last-planned graduation-date) - students who are not seeking a degree (e.g. continuing-education), in which case their isn't any further info. We'll have a named-constant CURRENT-YEAR, representing the first year which is not in the past. |# (define CURRENT-YEAR 2016) #| Note that each single line needs only a single piece of information, so we DON'T need a class/struct. Instead we want a *union* data type with four variants: so we have a single piece of information, and are able to use it to tell which of the four categories we are in, as well as the value (as appropriate). This is the piece of info which will get passed around to other functions as a single argument. [Brainstorm for a couple of minutes, then scroll down. There isn't any one correct answer. This is the toughest part of the problem, and usually I will provide a suggested data-definition. A planned-year is one of: - _________________________, OR - _________________________, OR - _________________________, OR - _________________________. To help get you started: in my solution, two of my four cases were: integers-less-than-CURRENT-YEAR, and negative integers.] part (a), my solution: A "planned-grad" is one of: - a number >= CURRENT-YEAR, OR - a positive integer < CURRENT-YEAR, OR - a negative integer, OR - 'non-degree-seeking. Well, some explanation might help -- not always required, if it's more obvious: - an integer >= CURRENT-YEAR, OR - a positive integer < CURRENT-YEAR (for already-graduated students), OR - a negative integer (for students whose expected graduation-date has passed: the negative of the number indicates what their now-passed expected date was -- thus its absolute-value is strictly less than CURRENT-YEAR), OR - 'non-degree-seeking (for non-degree-seeking students). Reflections [optional reading]: - It's definitely a bit hack-y to use negative-ints this way. (For example, it precludes having students who *actually* graduated before 1 A.D., which is not a problem in RU's case.) Alternately, we could have used a floating-point number (#i2014.0, instead of -2014, although this precludes students graduating in some long-future year, which isn't a problem ...YET) In both cases, we're "fighting" the language's built-in types to be able to have two different types of integers. Another approach might be having a list-of-exactly-one-int to represent a slipped graduation-date (and our code will look at whether we have an int, or a list, to distinguish), or perhaps a class/struct which simply holds one int inside (a "wrapper"). - some people want to make a class/struct that has four different fields, only one of which will hold "real" data, and perhaps an additional 'tag' field to indicate which of the four others is the one to really use. That code smells though: If you ever have fields that don't hold real data, you probably shouldn't have that field. What *would* be reasonable is having a tag indicating which case we have, and enough bits to hold the largest of the four cases. Then our program can look at the tag, and know how to interpret the remaining bits (e.g. 'just look at the first bit and treat is as a boolean', vs 'look at 32 bits and treat it as an int'). In fact, this tagged approach is how types are represented internally, in non-statically typed languages. OKAY -- perhaps I should have just *given* you a data-definition, but in real life figuring out the data definition yourself is the hardest part of writing a program. (b) Give examples of the data (at least four -- one for each case). |# ;; YOUR PART (b) HERE #| (c) Give a template, for any function which handles this data. That is, a function `handle-planned-grad`, which `cond` with four branches. |# ;; YOUR PART (c) HERE #| (d) Write the function `on-schedule?` which returns whether it's possible for the student to graduate by their grad-year. More precisely, it's not impossible for them to graudate by their planned year. (And for non-degree-seeking students, this function returns false.) Be sure to follow steps 4,5,6,7 of the design recipe -- they will all fall into place! |# ;; YOUR PART (d) HERE #| Other possible functions: "convert the planned-grad to a string, to be printed on their degree audit", and "is the student's planned-grad next year?", |# ; ; ; ;;; ;;; ; ; ;;; ;;;; ;;;; ;;;; ; ; ;; ;; ;; ; ;; ;; ;; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ;; ; ; ;; ;; ; ;; ; ; ;;;;; ;;; ; ; ; ;;;; ; ;;;;; ; ; ; ; ;; ; ;;; ; #| IGNORE THIS -- it was my first draft of a part(d) question. But it's a function that takes in *two* planned-grads, which makes a "4x4" set of inputs, which is more tedious than I want to do. (But, it's a good skill to know how to do, even though I'm not actually asking it.) |# ; (d) write the function "given two planned-grads, is the first no-later-than the other?" ; We'll call this `planned-grad<=`; here are some test-cases: ; planned-grad<= : planned-grad, planned-grad -> boolean ; Is the first plan to graduate no-later-than the other? (define (planned-grad<= yr1 yr2) #false) ;case 1 vs case 1 (check-expect (planned-grad<= 2018 2020) #true) (check-expect (planned-grad<= 2018 2018) #true) (check-expect (planned-grad<= 2018 2016) #false) ; case 1 vs cases 2,3,4 (check-expect (planned-grad<= 2018 2014) #false) (check-expect (planned-grad<= 2018 -2014) #false) (check-expect (planned-grad<= 2018 #false) #false) ; case 2 vs case 1 (check-expect (planned-grad<= 2014 2018) #true) ; case 2 vs case 2 (check-expect (planned-grad<= 2014 2015) #true) (check-expect (planned-grad<= 2014 2014) #true) (check-expect (planned-grad<= 2014 2012) #false) ; case 2 vs case 3 (check-expect (planned-grad<= 2014 -2016) #true) (check-expect (planned-grad<= 2014 -2012) #false) ; case 2 vs case 4 (check-expect (planned-grad<= 2014 #false) #false) ; case 3 vs case 1 (check-expect (planned-grad<= -2014 2018) #true) ; case 3 vs case 2 (check-expect (planned-grad<= -2014 2015) #true) (check-expect (planned-grad<= -2014 2012) #false) ; case 3 vs case 3 (check-expect (planned-grad<= -2014 -2015) #true) (check-expect (planned-grad<= -2014 -2014) #true) (check-expect (planned-grad<= -2014 -2012) #false) ; case 3 vs case 4 (check-expect (planned-grad<= -2014 #false) #false) ; case 4 vs case 1 (check-expect (planned-grad<= #false 2018) #false) ; case 4 vs case 2 (check-expect (planned-grad<= #false 2015) #false) ; case 4 vs case 3 (check-expect (planned-grad<= #false -2012) #false) ; case 4 vs case 4 (check-expect (planned-grad<= #false #false) #false)