Recursion and Preconditions


Due: 9 a.m. Wednesday, 11 March 2009

Summary: Write several procedures that safely and efficiently accomplish tasks by recursing over lists.

Purposes: To further practice writing recursive procedures, documenting procedures, and verifying preconditions.

Expected Time: Two to three hours.

Collaboration: We encourage you to work in groups of size three. You may, however, work alone or work in a group of size two or size four. You may discuss this assignment with anyone, provided you credit such discussions when you submit the assignment.

Submitting: Email your answer to . The title of your email should have the form HW7 and should contain your answers to all parts of the assignment. Scheme code should be in the body of the message.

Warning: So that this assignment is a learning experience for everyone, we may spend class time publicly critiquing your work.

Assignment

Problem 1: Reversing lists

a. Using the 6 P's, document the reverse procedure.

b. Suppose the reverse procedure were not included in Scheme. Could you write it yourself? Certainly! It should be possible to implement reverse recursively.

One strategy is to use the standard recursive formulation of

(define my-reverse
  (lambda (lst)
     (if (null? lst)
         base-case
         (combine (car lst) (my-reverse (cdr lst))))))

Finish this implementation.

When using this strategy, you'll need to think about this question: “Suppose I've reversed the cdr of a list. What do I do with the car to get the reversal of the complete list?

c. Of course, you've seen more than one strategy for writing recursive procedures. Another possibility is to use a helper that includes a “what I've done so far” parameter. For example,

(define my-other-reverse
  (lambda (lst)
     (my-other-reverse-helper null lst)))

(define my-other-reverse-helper
  (lambda (reversed-so-far remaining-elements)
    (if (null? remaining-elements)
        base-case
        (my-other-reverse-helper (modify reversed-so-far)
                                 (cdr remaining-elements)))))

Finish this implementation.

d. Take one of the versions of reverse that you just wrote and modify it so that it verifies its preconditions.

Problem 2: index-of, Revisited

The the lab on verifying preconditions offers the following definition of the index-of procedure, which finds the index of a value in a list.

(define index-of
  (lambda (val vals)
    ; If the value appears first in the list
    (if (equal? val (car vals))
        ; Then its index is 0.
        0
        ; Otherwise, we find the index in the cdr.  Since we've
        ; thrown away the car in finding that index, we need to add 1
        ; to get its index in the overall list.
        (+ 1 (index-of val (cdr vals))))))

a. What preconditions should index-of have?

b. Rewrite index-of using tail recursion and a husk and kernel. It should verify its preconditions.

Problem 3: Substitution

Note: This problem appears as Extra 1 in the lab on verifying preconditions.

Consider a procedure, (list-substitute lst old new), that builds a new list by substituting new for old whenever old appears in lst.

> (list-substitute (list "black" "red" "green" "blue" "black") "black" "white")
(list "white" "red" "green" "blue" "white")
> (list-substitute (list "black" "red" "green" "blue" "black") "yellow" "white")
(list "black" "red" "green" "blue" "black")
> (list-substitute null "yellow" "white")
()

a. Document this procedure, making sure to carefully consider the preconditions.

b. Implement this procedure, making sure to check the preconditions.

Problem 4: Substituting Colors, Revisited

Note: This problem appears as Extra 2 in the lab on verifying preconditions.

Consider a procedure, (spots-substitute spots old new), that, given a list of spots and two colors, makes a new copy of spots by using the color new whenever old appeared in the original spots.

a. What preconditions does this procedure have?

b. Implement this procedure, using the husk-and-kernel structure to ensure that old and new are rgb colors and that spots is a list of spots, before starting the recursion.

Extra Credit: Splitting Lists

Define and test a Scheme procedure, (unriffle lst), that takes a list as argument and returns a list of two lists, one comprising the elements in even-numbered positions in the given list, the other comprising the elements in odd-numbered-positions.

> (unriffle (list 'a 'b 'c 'd 'e 'f 'g 'h 'i))
((a c e g i) (b d f h))
> (unriffle (list))
(() ())
> (unriffle (list 'a))
((a) ())
> (unriffle (list 'b))
((b) ())
> (unriffle (list 'a 'b))
((a) (b))

Hint: There are many ways to solve this problem. Before writing code, try solving it by hand to develop your algorithm.

Important Evaluation Criteria

Students who provide correct procedures for each question will earn a check.

Students who provide exceptionally elegant solutions may receive a higher grade. Students who provide oddly formatted or inelegant solutions to the problems may be publicly critiqued for their odd formatting and inelegance, and will also receive a grade penalty.


Jerod Weinman