Functional Problem Solving (CSC 151 2015F) : Assignments

Exam 3: Advanced Scheming


Assigned: Tuesday, November 3rd, 2015

Due: The due dates for various tasks are as follows.

Important! This examination has an initial code file that you should copy and use as the starting point for your work.

Please read the information on this examination, which includes both instructions and a checklist.

Problems

Problem 1: Whatzitdo?

Topics: Numeric recursion, documentation, code reading.

Consider the following function definition for a function that takes a real number, x, and a non-negative integer, n, as parameters.

(define fun
  (lambda (x n)
    (cond
      [(zero? n)
       1]
      [(odd? n)
       (* x (fun x (- n 1)))]
      [else
       (square (fun x (/ n 2)))])))

Figure out what this procedure does.

a. Rename fun to something appropriate.

b. Write the 6P-style documentation for the renamed fun.

c. Explain how the procedure achieves its goal.

d. Write a short test suite for the renamed function. You should have approximately six tests, with at least three different values for x and at least three different values for n.

Problem 2: The Furthest Color

Topics: Integer-encoded RGB colors, recursion, named let, documentation, precondition testing.

In case you've forgotten, one of the simple metrics for the “distance” between two colors is the sum of the squares of the differences between their individual components.

;;; Procedure:
;;;   irgb-distance
;;; Parameters:
;;;   color1, an integer-encoded RGB color
;;;   color2, an integer-encoded RGB color
;;; Purpose:
;;;   Find the distance between color1 and color2, using some simple
;;;   metric for distance.
;;; Produces:
;;;   distance, a non-negative real number
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   If color1=color2, then distance is 0
;;;   For any three colors, a, b, and c, if 
;;;     (irgb-distance a b) < (irgb-distance b c)
;;;   then a is likely to be perceived as being closer to b than c.
;;; Plus:
;;;   irgb-distance is commutative.  That is, for any two colors, a and b,
;;;     (irgb-distance a b) = (irgb-distance b a)
(define irgb-distance
  (lambda (color1 color2)
    (+ (square (- (irgb-red color1) (irgb-red color2)))
       (square (- (irgb-green color1) (irgb-green color2)))
       (square (- (irgb-blue color1) (irgb-blue color2))))))

a. Document a procedure, (irgb-furthest color colors), that finds the element of colors that is furthest from color using irgb-distance as the distance for the metric.

b. Implement irgb-furthest. You must use named let for a recursive kernel for this procedure.

Here's a start.

(define irgb-furthest
  (lambda (color colors)
    (let kernel ([remaining (cdr colors)]
                 [guess (car colors)])
      ...)))

c. Add appropriate precondition testing so that irgb-furthest issues an appropriate error message when it receives incorrect inputs. You should strive to make sure that the error messages clearly correspond to the different kinds of errors that might occur.

Problem 3: String to Words

Topics: Strings, numeric recursion.

Write but do not document a procedure, (string->words str), that takes a string str as input and returns a list of strings, each containing one word from the input string. You may assume words are separated by spaces.

Here are some example uses of string->words.

> (string->words "Hello World")
'("Hello" "World")
  
> (string->words "Words may include punctuation. That is okay!")
'("Words" "may" "include" "punctuation." "That" "is" "okay!")
  
> (string->words "")
'("")
  
> (string->words "oneword")
'("oneword")

> (string->words "two  spaces")
'("two" "" "spaces")

Problem 4: Another Whatzitdo?

Topics: Strings, higher-order procedures, map, documentation.

Some time ago, a student who I will call “Gle” came up with something like the following as an alternative to an existing procedure.

(define f (lambda (a b c) (list->string (map (o (l-s string-ref a) (l-s + b)) (iota (- c b))))))

Figure out what the procedure does and then do the following.

a. Rename the procedure and the parameters so that their type and purpose is clearer.

b. Reformat the code.

c. Document the updated procedure.

Problem 5: Scripting Turtles

Topics: Turtle graphics, using actions, for-each

Sometimes it's useful to make lists of actions for a turtle to complete. For example, to make a triangle, we can have "forward 10, turn 120, forward 10, turn 120, forward 10". In Scheme, we might represent each action as a one-parameter procedure. For example, (r-s turtle-forward! 10) or (lambda (t) (turtle-teleport! t 100 100)).

Write but do not document a procedure, (turtle-script! turtle script!) that has the turtle follow a script, where the script is a list of one-parameter procedures. You may not use explicit recursion.

Here's the documentation for turtle-script!.

;;; Procedure:
;;;   turtle-script!
;;; Parameters:
;;;   turtle, a turtle
;;;   script, a list of one-parameter functions
;;; Purpose:
;;;   Have turtle execute the actions in script one by one
;;; Produces:
;;;   turtle, the same turtle
;;; Preconditions:
;;;   script has the form '(action-1! ... action-n!)
;;;   Each action is a procedure of one parameter that takes a turtle
;;;     as input.
;;; Postconditions:
;;;   The following actions have been executed in turn
;;;     (action-1! turtle)
;;;     (action-2! turtle)
;;;     ...
;;;     (action-n! turtle)

Here are a few examples.

(turtle-script! (turtle-new (image-show (image-new 200 200)))
                (list (section turtle-teleport! <> 100 50)
                      (r-s turtle-face! 90)
                      (r-s turtle-forward! 80)
                      (r-s turtle-set-color! "red")
                      (r-s turtle-turn! -45)
                      (r-s turtle-forward! 30)
                      (r-s turtle-set-color! "grey")
                      (r-s turtle-turn! -90)
                      (r-s turtle-forward! 60)
                      (r-s turtle-set-color! "blue")
                      (r-s turtle-face! 180)
                      (r-s turtle-forward! 100)))
(define side-script 
  (list (r-s turtle-forward! 100)
        (r-s turtle-turn! 90)))
(define square-script
  (append (list (lambda (t) (turtle-teleport! t 50 50))
                (r-s turtle-set-color! "green"))
          side-script side-script side-script side-script))
(turtle-script! (turtle-new (image-show (image-new 200 200)))
                square-script)

Problem 6: Drawing a Tree with Turtles

Topics: Turtle drawings, recursion, recursion with helpers, numeric recursion, documentation.

Write and document a procedure, (turtle-tree! turtle trunk-length branches levels), that uses the provided turtle to draw a tree. You can think of a tree as a trunk (a line) with some number of smaller trees "growing" out of the end of the trunk.

To draw a tree, your turtle should rotate to a random angle between plus and minus 60 degrees, then draw a line that is trunk-length pixels long. The end of the trunk should split into some number of smaller trees, determined by the branches parameter. Each smaller tree should have a slightly shorter trunk length (75% of the previous trunk length works well). This process should repeat until the tree has levels levels; for example, if branches and levels are both 3, the tree should have a total of 13 lines. Before drawing a tree, some set-up is required:

; Create a world, a turtle, set the brush to a fine line, and position the turtle
; at the bottom middle of the image facing up.
(define set-up-turtle
  (lambda ()
    (let* ([world (image-show (image-new 300 200))]
           [tommy (turtle-new world)])
      (turtle-turn! tommy -90)
      (turtle-teleport! tommy 150 200)
      (turtle-set-brush! tommy "2. Hardness 100" 0.15)
      tommy)))

After running the set-up code above, you should be able to run the following examples with a completed turtle-tree! function.

; Draw a tree with a trunk length of 60, three branches, and three levels.
(turtle-tree! (set-up-turtle) 60 3 3)
; Draw a larger tree, this time with five branches and four levels.
(turtle-tree! (set-up-turtle) 60 5 4)
; Draw another large tree. Trees don't always grow straight!
(turtle-tree! (set-up-turtle) 60 5 4)
; Draw a very large tree with seven branches and five levels. This will take quite a while.
(turtle-tree! (set-up-turtle) 60 7 5)

Some Questions and Answers

Here we will post answers to questions of general interest. Please check here before emailing your questions!

General Questions

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?
More or less.
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 tutor 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.
If we get more than 70 points, does the “There's more to life” clause drop our grade to 70?
No! The “There's more to life” clause provides a minimum grade for people who do appropriate amounts and type of work and provide evidence of some mastery.
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?
That's one of the reasons we give extra credit to those who work on the exam early. But you're also better able to get your questions answered early if you start early (or at least we think you are). 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 one in class. If you need a new one, there's a stack in the back of our classroom.
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”.
What is this STUB comment that appears in the code file?
We typically use the term “STUB” to indicate that we've put in a piece of code to get the program to run, but that the code is intended only as a placeholder until we write something correct.
I know that you prefer that lines be under 80 characters. But what if I'm citing a Web page and the URL is longer than 80 characters? [2015-11-08]
In that particular case, it's fine that the line is longer than 80 characters.

Problem 3

I see from the examples that if there are multiple spaces in a row, we get to treat each space as a word break. I find that inelegant. Is it okay if I treat a sequence of spaces as a single space? [2015-11-05].
Yes. That's probably even preferable. But we thought it was harder, so we did not require it.
What should (string->words "Hello world ") return? In other words, how should we handle extra spaces at the end of a string?
Your implementation could return '("Hello" "world") or '("Hello" "world" ""). The result '("Hello" "world ") would not receive full credit; string->words should never return words that contain spaces.

Problem 5

What do you mean by “explicit recursion”? [2015-11-05]
A procedure that calls itself (or a pair of procedures that call each other.) However, you don't know how every procedure we provide you with has been implemented, so when you use for-each or repeat, you may be implicitly be using recursion. Implicit recursion is okay.
I seem to recall that you taught us how to write procedures that take other procedures as parameters. Can you give me another example? [2015-11-07]
The following procedure takes another procedure as input and applies it to the value 4.
(define apply-to-4
  (lambda (proc)
    (proc 4)))
> (apply-to-4 square)
16
> (apply-to-4 sqrt)
2
> (apply-to-4 increment)
5
> (apply-to-4 (r-s expt 3))
64
> (apply-to-4 (lambda (val) (* 3 (+ val 2))))
18
Can you help me think about this problem? [2015-11-07]
We've suggested that you think about using for-each, so think about the types of parameters to for each. One of those parameters is a procedure. What is the input type to that procedure? [2015-11-07]
Since we are using the procedure to generate images, how do we give sample output? [2015-11-10]
You can simply show that it runs correctly on our samples by giving the inputs from the exam. No need to include images.

Problem 6

Are we allowed to clone the turtle along the way? [2015-11-05]
Yes. It is much harder to do the problem if you don't clone the turtle. (Of course, if you'd like to take on that challenge, we couldn't object.)
Do you turn the turtle before drawing the branch? [2015-11-07]
Yes. As the examples suggest, in most cases the first branch (the trunk?) does not start out vertically.
Since we are using the procedure to generate images, how do we give sample output? [2015-11-10]
You can simply show that it runs correctly on our samples by giving the inputs from the exam. No need to include images.

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.)

  • Missing periods in the comments in the code for problem 6. [EB, 1/2 point]
  • Incorrect number of problems on prologue in SR's class. [AB, 1 point for SR's class]
  • Extra paren in problem 5. [GN, ES, and SJ, 1 point]
  • trunnk-length instead of trunk-length in the sample code file. [RS, GN, and ZS, 1/2 point]

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 Janet Davis, Rhys Price Jones, 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.