Skip to main content

Exam 1: Scheme basics

Assigned: Wednesday, February 8

Prologue Due: Friday, February 10 by 10:30pm

Exam Due: Tuesday, February 14 by 10:30pm

Epilogue Due: Wednesday, February 15 by 10:30pm

Please read the exam procedures page for policies, turn-in procedures, and grading details. If you have any questions about the exam, check the Q&A at the bottom of this page. We will generally spend some time in class every day on questions and answers while the exam is in progress.

While the exam is out, please check back periodically to see if we have reported any new errata.

Complete the exam using the exam1.rkt starter source code. Please rename this file to 000000.rkt, but replace 000000 with your assigned random number.

Problem 1: Adding three

Topics: documentation, defining procedures with compose, defining procedures with section, defining procedures with lambda

We have now learned three different ways to write procedures.

  1. We can use function composition.

  2. We can use sectioning.

  3. We can use lambda.

a. Write the 6P-style documentation for a procedure, add3, that adds three to its argument.

b. Implement add3 using function composition. To avoid name overlap, you can call this add3b. You may not use sectioning, lambda, or other procedures you define in implementing add3b.

c. Implement add3 using sectioning. To avoid name overlap, you can call this add3c. You may not use composition, lambda, or other procedures you define in implementing add3c.

d. Implement add3 using lambda. To avoid name overlap, you can call this add3d. You may not use sectioning, composition, or other procedures you define in implementing add3d.

Problem 2: Increasing contrast

Topics: irgb colors, writing procedures, image-variant

Sometimes an image can look “washed out” if the difference between light and dark colors is not sufficiently large. We can increase the contrast of an image by increasing the magnitude of bright color components and decreasing the magnitude of darker color components.

Write, but do not document, a procedure (irgb-increase-contrast color amount). This procedure should return a new color which we will call result. If the red component of color is less than 128, the red component of result should be less than that of color. If the red component of color is greater than 128, then the red component of result should be larger than that of color. The same rules apply to the green and blue components.

The amount parameter should control how much the components change, but the exact meaning of this parameter is up to you. The one requirement is that a larger value for amount should result in a larger change in each component.

Here is an example run of irgb-increase-contrast:

> (define kitten (image-load "/home/rebelsky/Desktop/kitten.jpg"))
> (define contrast-kitten
    (image-variant kitten (section irgb-increase-contrast <> 1.6))

Here is the original image:

> (image-show kitten)

The original kitten image

And here is one example of the kitten with increased contrast.

> (image-show contrast-kitten)

The same image with contrast increased using one possible implementation of irgb-increase-contrast

Note: your implementation may produce different results for a given amount. You may submit any implementation where increasing amount increases the change in contrast.

Problem 3: Whatzitdo?

Topics: arithmetic operators, code reading, documentation

Sometimes students (and professors) come up with difficult-to-read solutions to simple problems, like this one below:

(define z (lambda 
(w x y) (- 
        (+ w y (* 2 x)) 
    (min w x y) x (max w x y))))

a. Clean up this procedure. You should reformat the code (add carriage returns and indent to format clearly); rename the procedure, parameters, and variables; and simplify any unnecessarily complicated code.

b. Write 6P-style documentation for the code.

c. Explain how the code achieves its purpose.

Problem 4: Shades

Topics: RGB colors, Color transformations, lambda

Recall that on a recent assignment, you wrote a procedure that did “gamma correction” on images. If we do gamma correction on a single color, we get something that might be called a “shade” of that color. (Our colleage in Studio Art, Matt Kluber, says that there is no such thing as a “shade”, but you know what we mean.)

Write, but do not document, a procedure, (shades color), that takes as input an integer-encoded RGB color and produces a swatch of five colors:

  • the color gamma corrected by 0.5,
  • the color gamma corrected by 0.75,
  • the color gamma corrected by 1.0,
  • the color gamma corrected by 1.25, and
  • the color gamma corrected by 1.5.

If you were not able to implement gamma correction, contact your instructor for a solution.

Problem 5: Adding times, revisited

Topics: code reading, representing times, complex numbers, numeric computation, abusing Scheme

Suppose we want to do math with times, and we limit ourselves to times that involve minutes and seconds. How do we represent both minutes and seconds? Here’s a not-necessarily-clever trick: We could use complex numbers. The real part of the imaginary number represents the minutes and the imaginary part represents the seconds.

Here are some procedures that allow us to work with that representation.

;;; Procedure:
;;;   time
;;; Parameters:
;;;   min, a non-negative integer
;;;   sec, a non-negative integer
;;; Purpose:
;;;   Generate a representation of min minutes and sec seconds
;;; Produces:
;;;   tm, a complex number representing a time
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   (minutes tm) = min
;;;   (seconds tm) = sec
(define time
  (lambda (min sec)
    (+ min (* 0+i sec))))

;;; Procedure:
;;;   minutes
;;; Parameters:
;;;   tm, a complex number representing a time
;;; Purpose:
;;;   Extract the minutes from tm
;;; Produces:
;;;   min, an integer
(define minutes real-part)

;;; Procedure:
;;;   seconds
;;; Parameters:
;;;   tm, a complex number representing a time
;;; Purpose:
;;;   Extract the seconds from tm
;;; Produces:
;;;   sec, an integer
(define seconds imag-part)

;;; Procedure:
;;;   display-time
;;; Parameters:
;;;   tm, a complex number representing a time
;;; Purpose:
;;;   Display the time.
;;; Produces:
;;;   [Nothing; called for the side effect]
(define display-time
  (lambda (tm)
    (display (minutes tm))
    (display " minutes and ")
    (display (seconds tm))
    (display " seconds.")
    (newline)))

Write and document a procedure, (add-times time1 time2), that adds the two times appropriately. For example,

> (define t1 (time 5 35))
> (minutes t1)
5
> (seconds t1)
35
> (display-time t1)
5 minutes and 35 seconds.
> (define t2 (add-times t1 t1))
> (minutes t2)
11
> (display-time t2)
11 minutes and 10 seconds.
> (display-time (add-times t1 t2))
16 minutes and 45 seconds.

Your procedure should correctly limit the number of seconds to between 0 and 59, even if the input time is not in that form.

> (define t3 (time 0 97))
> (display-time t3)
0 minutes and 97 seconds.
> (define t4 (add-times t3 t3))
> (display-time t4)
3 minutes and 14 seconds.
> (display-time (add-times (time 0 0) t3))
1 minutes and 37 seconds.

Problem 6: Flattening

Topics: RGB colors, color transformations, clever numeric computation

A common technique for manipulating images is known as “flattening” the image. In general, we flatten an image by restricting the values of each component to multiples of a certain value. For example, we might ensure that the components are each multiples of 16, 32, or 64. (We’ll use 255 instead of 256 for the highest multiple.)

a. Write and document a procedure, (irgb-flatten irgb-color val), that flattens an IRGB color by converting each component to the nearest multiple of val.

> (define c1 (irgb 74 179 221))
> (irgb->string (irgb-flatten c1 10))
"70/180/220"
> (irgb->string (irgb-flatten c1 64))
"64/192/192"

If the nearest multiple is over 255, you can rely on the irgb procedure to convert it to 255.

> (irgb->string (irgb-flatten (irgb 77 23 252) 100))
"100/0/255"     ; The nearest multiple of 100 to 252 is 300.

b. Using irgb-flatten, write, but do not document, a procedure (image-flatten image val) that flattens an image by flattening each pixel in the image so that each component is converted to the nearest multiple of val.

You will receive a modicum of extra credit if you can define irgb-flatten or image-flatten without relying on lambda.

Questions and Answers

We will post answers to questions of general interest here while the exam is in progress. Please check here before emailing questions!

General Questions and Answers

What is a general question?
A question that is about the exam in general, not a particular problem.
Do the two sections have the same exam?
Yes.
Can we still invoke the “There’s more to life” clause if we spend more than five hours on the exam?
Yes. However, we really do recommend that you stop at five hours unless you are very close to finishing. It’s not worth your time or stress to spend more effort on the exam. It is, however, worth your time to come talk to us, and perhaps to get a mentor or more help (not on this exam, but on the class). There’s likely some concept you’re missing, and we can help figure that out.
What do you mean by “implement?”
Write a procedure or procedures that accomplish the given task.
Do we have to make our code concise?
You should strive for readable and correct code. If you can make it concise, that’s a plus, but concision is secondary to readability and correctness. Long or muddled code is likely to lose points, even if it is correct.
Much of your sample 6P-style documentation has incomplete sentences. Can we follow that model? That is, can we use incomplete sentences in our 6P-style documentation?
Yes, you can use incomplete sentences in 6P-style documentation.
You tell us to start the exam early, but then you add corrections and questions and answers. Isn’t that contradictory? Aren’t we better off waiting until you’ve answered the questions and corrected any errors?
We think you’re better able to get your questions answered early if you start early. Later questions will generally be told “See the notes on the exam.”
How do we know what our random number is?
You should have received instructions on how to generate your random number on the day the exam was distributed. If you don’t have a number, ask your professor for one before submitting your exam.
To show we’ve tested the code informally, would you just like us to just post the inputs we used to test the procedure? If so, how should we list those?
Copy and paste the interactions pane into the appropriate place in the definitions pane. Select the text. Under the Racket menu, use “Comment out with semicolons.”
Should we include examples and, if so, how do we include them?
You should certainly include examples. We would recommend that you copy and paste them from the interactions pane to right below the problem in the definitions pane, and then comment them out with semicolons. (Select and then choose “Comment out with semicolons” from the “Racket” menu. Do not use “Comment out with a box!”)
Should we cite our partner from a past lab or assignment if we use code from a past lab or assignment?
You should cite both yourself and your partner, although you should do so as anonymously as possible. For example “Ideas taken from the solution to problem 7 on assignment 3 written by student 641321 and partner.”
If we write a broken procedure and replace it later, should we keep the previous one?
Yes! This will help us give you partial credit if your final procedure isn’t quite right.
What is the symbol 'STUB that appears throughout the exam file?
We use the term 'STUB when we need to fill in a placeholder in code for what you are going to write in the exam.
How should I fill out the time log?
Something like the following.
; Time Log:
;   Date        Start   Finish  Elapsed Activity
;   2017-02-08  14:00   14:15   0:15    Tried to understand problem, wrote prelim docs 
;   2017-02-09  18:00   18:20   0:20    Finished documenting
;   2017-02-09  19:00   19:20   0:20    Draft of procedure.  Works for most cases, but not black and white.
;   2017-02-10  01:00   01:10   0:10    Woke up in the middle of the night with the solution
;   2017-02-10  09:00   09:05   0:05    Minor cleanup

; Time Spent: 1:10

Questions on problem 1: Adding three

Can I use section in my solution that uses composition?
No. Composition should rely just on composition.
Any hints on how to solve this using composition?
Review the reading that introduced composition.

Questions on problem 2: Increasing contrast

Can I change the preconditions to require that amount is greater than
one?
Yes.
Can I require that the components be neither 0 nor 255 for me to increase
the contrast?
Yes. We’ve revised the postconditions to make that clear.

Questions on problem 5: Adding times, revisited

Can we use the provided procedures?
You should use the provided procedures.
Any other hints?
Try expressing the result in English. “If I add t1 and t2, the number of minutes in the result should be … and the number of seconds should be ….”
I’m not sure that I understand complex numbers.
You don’t need to worry about the complex numbers. You should never deal with them directly.
I don’t understand why it says that display-time produces “[Nothing; called for the side effect]”.
It’s one of those output vs. return issues. Consider the following releated procedures.
(define p1
  (lambda (val)
    (display "[")
    (display val)
    (display "]")
    (newline)
    val))

(define p2
  (lambda (val)
    (display "{")
    (display val)
    (display "}")
    (newline)))

Both p1 and p2 display val with symbols around it. But p1 then returns (produces) the same value it was given, while p2 returns (produces) nothing. We can see the difference if we try to use them.

> (+ 1 (p1 5))
[5]
6
> (+ 1 (p2 5))
{5}
. . +: contract violation
  expected: number?
  given: #<void>
  argument position: 2nd
  other arguments...:

Errata

Here you will find errors of spelling, grammar, and design that students have noted. Remember, each error found corresponds to a point of extra credit for everyone. We usually limit such extra credit to five points. However, if we make an astoundingly large number of errors, then we will provide more extra credit. (And no, we don’t count errors in the errata section or the question and answer sections.)

Problem 2: Increasing contrast

  1. The line (define kitten (image-load "/home/rebelsky/Desktop/kitten.jpg")) was missing a right parenthesis. [+1 YC]
  2. The postconditions, as stated in the file, are impossible to acheive for components of 0 or 255 [+0 CM]

Problem 3: Whatzitdo?

  1. Carriage return was mispelled. [+1 IX]

Problem 5: Adding times, revisited

  1. In the sample code, an “add times” was supposed to be “add-times,” and the output “0 minutes and 96 seconds” was supposed to be “0 minutes and 97 seconds.” [+1 RL]

Problem 6: Flattening

  1. The wording “A common common” should have been “A common” instead. [+1 MT,AH]
  2. One occurrence of “irb-flatten” should have been “irgb-flatten” [+1 MT]
  3. The output of (irgb->string (irgb-flatten c1 64)) should have been "64/192/192" instead. [+0 IX]

Citations

Some of the problems on this exam are based on (and at times copied from) problems on previous exams for the course. Those exams were written by Charlie Curtsinger, Janet Davis, Rhys Price Jones, Titus Klinge, Samuel A. Rebelsky, John David Stone, Henry Walker, and Jerod Weinman. Many were written collaboratively, or were themselves based upon prior examinations, so precise credit is difficult, if not impossible.

Some problems on this exam were inspired by conversations with our students and by correct and incorrect student solutions on a variety of problems. We thank our students for that inspiration. Usually, a combination of questions or discussions inspired a problem, so it is difficult and inappropriate to credit individual students.