6 Putting conditionals and words and sentences together
(5 activities)
6.1 Quiz: "Working with Conditionals".(1 step)
6.1.1 (Student Assessment) Write a procedure using only cond then using only if
When programming there are a lot of different ways that you can solve any problem. Below you're going to solve a problem in two ways. The first time you solve it you can only use if statements. The second time you solve it you can only use if statements.

Write a procedure named comfort-level that, given a Celsius temperature as argument, returns an indicator of how comfortable the temperature is.

  • If the temperature is less than 10, comfort-level should return the word too-cold.
  • If the temperature is between 10 and 30, inclusive, comfort-level should return the word comfortable.
  • If the temperature is greater than 30, comfort-level should return the word too-hot.
1.Write the procedure comfort-level using cond (without using if)
2.Write the procedure comfort-level using ifs(without using cond)
6.2 Use good names and provide good comments.(2 steps)
6.2.1 (Display page) Programs should read like English.

Programs should read like English.

Programs are written partly to be run; that's how work gets done with the computer. The Scheme interpreter will run your program regardless of the names you use for procedures and placeholders. For example,
(define (foo q)
  (* q q) )
is understood by the Scheme interpreter to be the same thing as

(define (square num)
  (* num num) )
Programs are also written to be read by people, however. People might include your instructor or supervisor, your project partner, or even yourself (reading a program a couple of months after you wrote it, and trying to figure out what you meant). Good choices for procedure and placeholder names, as well as good use of comments, can make it significantly easier for someone to understand how to use your program, what it's supposed to do, and how to modify it if necessary.

Adding comments to your code

Comments start with a semicolon, and are completely ignored by the Scheme interpreter. It is good practice to make an entire line a comment; that is, start the line with a semi-colon. (There are other ways to specify comments we will talk about later). Because comments are ignored by Scheme, they are only relevant for someone reading the program. Programmers typically accompany each procedure they write with a comment that says what the procedure expects as arguments and what it will return for given arguments. Examples of how a procedure is supposed to behave are good to include as part of the explanation. Here is a sample procedure with some comments:
;;square:  takes a number and squares it
; note:  don't use it with anything except numbers
; written by:  clint, 18 June 2003
(define (square num)
  (* num num))

Choosing good names for procedures and variables

Good choices for names depend on the situation. For parameters, a good name gives some idea of the type of value it represents for example, num in the square procedure above. This name explains that you're not expecting to multiply a word by itself. Typically, the name of a procedure that returns a number, a word, or a sentence is a noun that represents the value returned. The name of a predicate procedure one that returns true or falseis conventionally an verb. This is because such procedures are typically used with if, for example:
(if (is-legal? x) ... )
(if (is-number? x) ... )
(if (is-word? x) ... )
The built-in predicates are not always named as well as they could be. One always has to balance information communicated by a name with the length of that name (a name that's 100 characters long won't be very readable!), and the designers of Scheme valued conciseness a bit more than readability.
6.2.2 (Brainstorm) Provide a good name for a procedure
Here's a mystery procedure written by a programmer who chose terrible names. Provide a good comment for the procedure and replace its names with words that communicate much better what the procedure does. Check the other students answers. Did they make the code really easy to understand? Are there comments that don't really explain the code?
; useless comment
(define (x y)
  (word 'un y) )
6.3 Use helper procedures.(6 steps)
6.3.1 (Display page) Helper procedures can make a program more understandable.

Helper procedures can make a program more readable and more writable.

The built-in procedures first, butfirst, sentence, and word are named well enough to tell the reader of a program what it's doing, but not why. Here's an analogy in real life of how terms at this level of detail might not be the best possible way to communicate:
You (to your friend): What are you doing?
Your friend, responding in obnoxious low-level terms:  
  I'm typing an 's'.  
  Now I'm typing an 'e'.
Proper answer:
  I'm doing my CS 3 homework.
A good programmer often defines procedures that don't do much other than provide a good high-level name for a low-level operation. For example, when working with the programs in measurements.scm, you might define helper procedures named feet and inches and use them instead of first and second. Helper procedures are also useful when writing a procedure in the first place. Often a programmer can see how to solve some part of the problem, and writes a helper procedure to do this. Naming that helper procedure can help with designing the rest of the complete procedure to design (and also make the whole solution more readable).
6.3.2 (Display page) Analyze and simplify a procedure by defining helper procedures.

Analyze and simplify a procedure by defining helper procedures.

Here's a procedure that checks whether its arguments represent a valid date in the Gregorian calendar (the one we use in the United States). Simplify it and make it more readable by defining and using well-named helper procedures. When you are done, there should be more code than when you started, but it should be easier to understand. Put you new code, with helper functions, in a file called legal-date.scm.
; Return true if the arguments represent a legal date
; in the Gregorian calendar (instituted at the end of 1582).
; (Dates in the future are legal.)
(define (valid-date? day month year)
  (cond ((or (< day 1) (> day 31) 
             (< month 1) (> month 12) (<= year 1582))
         #f)
        ((= day 31) (member? month '(1 3 5 7 8 10 12)))
        ((= day 30) (not (= month 2)))
        ((and (= day 29) (= month 2))
         (cond ((divisible? year 400) #t)
               ((divisible? year 100) #f)
               ((divisible? year 4) #t)
               (else #f) ) )
        (else #t) ) )

(define (divisible? num1 num2)
  (= 0 (remainder num1 num2)))
6.3.3 (Display page) Compare your helper procedures with others.
There are many different ways to break down the valid-date? program using helper procedures. Share your code with someone else in the class. Which code do you think is easiest to read and understand? Which do you think is the hardest to read?
6.3.4 (Brainstorm) What did you see?
What makes code easy or hard to understand? What will you do to make your own code easier to read?
6.3.5 (Display page) Now test it

Test it to death

When programmers simplify code, it is easy to break the code they are supposed to be simplifying. To address this problem, what programmers do in industry is run a ton of tests on the old program and the new program to make sure they do the same thing Give your code a serious testing! When you think you are done, trade code with another group to see if you can break each other's simplified version. What test cases can you think of that the other group might not have. Make sure to explain any bugs you caught in the other team's code.
6.3.6 (Display page) Using comments to include test cases in your files
The scheme that we use has another way to include comments: surrounding text by #| (at the beginning) and |# at the end. Scheme will ignore anything within these tags. (Most Scheme dialects know about this comment method, but not all do). Although less simple to use than starting a line with a semicolon, these comments can span multiple lines. As such, they are a convenient way to include test cases in the same file as the procedure you wish to test. For example:
;; Square: takes a number and returns its square
;  written by Clint, 18 June 2003
(define (square num)
  (* num num))


#| Test Cases for square

; should return 9
(square 3)

; should return 9
(square -3)

; should give an error
(square 'three)

|#
By including the test cases inside a multi-line comment, they will not be evaluated when the entire file (or emacs buffer) is loaded. However, you can easily copy the individual test cases (or all of them) from your file into your Scheme listener and run them -- simply copy the text just inside the comment tags #| and |#. Adding semicolon comments within a multi-line comment, which is not necessary when the whole file is evaluated, makes copying the test cases easier.
6.4 Write larger procedures.(2 steps)
6.4.1 (Display page) Write an answer procedure.

Write an answer procedure. (This will be part of your homework for this lab).

Write a procedure named answer that, given a sentence that represents a question, returns a simple answer to that question. (A question's last word ends with a question mark.) If the argument sentence is not a question, answer should merely return the argument unchanged. Here's how the answer procedure should process different kinds of questions.
  • Given ( am i ...? ), answer should return ( you are ...).
  • Given ( are you ...? ), answer should return ( i am ...).
  • Given ( some-other-word i ... ? ), answer should return ( you some-other-word ...).
  • Given ( some-other-word you ... ? ), answer should return ( i some-other-word ...).
  • Given any other question, answer should return the result of replacing the question mark by a period.
IMPORTANT: Scheme has some problems with periods. (More correctly, a period means something special in Scheme, and different than punctuation that comes at the end of a english sentence.) You need to put a period in double quotes ("). For example, if you want to put a period at the end of the word "weasel," you would use this code: (word 'weasel ".")
For your homework you will put your solution, along with a comprehensive set of test calls for each procedure, into a file named answer.scm inside the lab4 directory. Make sure to use good names and helper procedures to make your program as readable as possible. For this program, you should feel free to collaborate in the initial stages. It will be turned in and graded, but we will be more lenient about collaborative work for this assignment. Certainly, work with your fellow students to understand the problem, and to break it down into logical pieces. You can work together on some of the coding, but you should do the majority of the coding individually. If some of the coding is shared, note with a comment what was shared and with whom.
6.4.2 (Display page) Write a time-of-day procedure.

Write a time-of-day procedure.

Write a procedure named time-of-day that, given a non-negative integer that represents the number of minutes after midnight for that day, returns the time of day in the format described below. Put this procedure, along with a comprehensive set of test calls, in a file named daytime.scm. There are several cases for the format of a time of day.
  • Noon and midnight are represented by the words noon and midnight respectively.
  • An afternoon time (between noon and midnight) should be represented by a sentence whose second word is pm and whose first word has the form hours:minutes, where hours is between 1 and 12 and minutes is a two-digit number of minutes. An example: (7:05 pm).
  • Similarly, a morning time should be a two-word sentence whose second word is am and whose first word has the form hours:minutes.
One way to get started on a big program like this is to try to write some helper procedures. Here are some suggested helper procedures - You may not need all of them, but they will probably be a good way to get warmed up. Can you think of any others you might want?
  • ;; Use the number of seconds to get the hour of that day.
    ;; It will return a number between 0 and 23.
    (define (number-of-hours seconds) ... )
  • ;; Use the number of seconds to get the minutes past the hour
    ;; It will return a number between 0 and 59.
    (define (number-of-minutes seconds) ... )
  • ;; Returns #t if the seconds provided represents noon.
    (define (is-noon? seconds) ... )
  • ;; Returns #t if the seconds provided represents midnight.
    (define (is-midnight? seconds) ... )
  • ;; Returns #t if the seconds provided represents an AM time.
    (define (is-AM-time? seconds) ... )
  • ;; Returns #t if the seconds provided represents a PM time.
    (define (is-PM-time? seconds) ... )

Note: Don't worry if your answer comes out surrounded by double quotes (like "7:05" instead of 7:05). If you want to get rid of decimal points after numbers, you can use the inexact->exact procedure. As an example, (inexact->exact 1.0) returns 1.
6.5 Homework(2 steps)
6.5.1 (Display page) Homework for next session

Homework

  1. Read the "Difference Between Dates" case study, part I. You can find it in the reader. (It is crucial that you read this before coming to the next two lab sessions!)
  2. Go back to the last homework's discussion activities and for each, make two thoughtful comments on other people's posts.
  3. You will need to complete the first part of this homework before doing this step. CS 3 students sometimes ask, "Why did you bother with showing us the dead-end solution? Why not just show us the 'right' solution?" What do you think about that? Contribute a post to this question in the step titled "Comment on seeing 'bad' solutions".
  4. Write answer.scm, as detailed in an earlier step. Be sure to include comprehensive tests. Submit this program by:
    • From within unix, moving to the lab4 directory, or wherever you put answer.scm.
    • Typing submit hwk4. It is crucial that your file be named answer.scm !
6.5.2 (Discussion Forum) Comment on seeing "bad" solutions.
The first solution presented in the "Difference Between Dates" case study was a dead end. Is it a good idea to study "bad" solutions? Provide an answer and an explanation. Next homework, we will ask you to comment on the answer of one of your classmates.