Skip to main content

Recursion basics

Summary: In this laboratory, you will explore some basic concepts in recursing over lists.

Preparation

a. Discuss the self check with your partner.

b. Do the normal lab setup. That is

  • Start DrRacket.
  • Make sure that the csc151 package is up to date.
  • Add (require csc151) to the top of the definitions pane.

c. Add the procedures and associated documentation from the corresponding reading to the definitions pane. Be sure to include a short note as to the source of that code.

d. Create a list named mixed-values that contains a dozen or so different kinds of values. You will likely use an instruction like the following.

(define mixed-values
  (list 1 'two "three" 4.5 6/7 (list) (list 8) 9+10i ...))

Exercises

Exercise 1: Testing the sum procedure

a. Read through sum so that you have a sense of how it accomplishes its purpose.

b. Verify that sum produces the same results as in the corresponding reading.

c. What value do you expect sum to produce for the empty list?

d. Check your answer experimentally.

e. What value do you expect sum to produce for a singleton list? (A “singleton list” is a list with only one value.)

f. Check your answer experimentally.

g. Try sum for a few other lists, too.

h. What do you expect the following to compute?

> (sum 1 2 3)

i. Check your answer experimentally.

Exercise 2: Selecting numbers

a. Reread the definition of select-numbers to try to understand what it does. Then copy the code into your definitions pane.

b. Determine which values in mixed-values are numbers with (map number? mixed-values).

c. Create a list of numbers with (select-numbers mixed-values).

d. Verify that all the resulting values are numbers, using a technique similar to the one that you used in step b.

Exercise 3: Counting values

Suppose the length procedure, which computes the length of a list, were not defined. We could define it by recursing through the list, counting 1 for each value in the list. In some sense, this is much like the definition of sum, except that we use the value 1 rather than the value of each element.

a. Using this idea, write a recursive procedure, (list-length lst) that finds the length of a list. You may not use length in defining list-length.

b. Check your answer on a few examples: the empty list, the list of values you created, and a few more lists of your choice.

Exercise 4: Product

Write a recursive procedure, (product nums), that computes the product of a list of numbers. You should feel free to use sum as a template for product. However, you should think carefully about the base case.

Exercise 5: Counting special values

The length procedure counts the number of values in a list. What if we don’t want to count every value in a list? For example, suppose we only want to count the numbers in a mixed list. In this case, we still recur over the list, but we sometimes count 1 (when the element is a number) and sometimes count 0 (when it is not).

a. Using this idea, write a procedure, (tally-numbers lst), that, given a list, counts how many are numbers. Note: You should not call list-length, length, filter, tally, or select-numbers in your solution. Instead, use the ideas behind some or all of these functions in crafting your own recursive solution.

b. Check how your procedure functions on a variety of inputs. For example, you might start with the following

> (tally-numbers null)
> (tally-numbers (list 1 2 3))
> (tally-numbers (list "a" "b" "c"))
> (tally-numbers (list 1 "a" 2 "b" 3 "c"))
> (tally-numbers mixed-values)

Exercise 6: The largest element in a list

Using recursion (hence, without reduce or sort or any similar procedure), write a procedure, (largest lst), that finds the largest value in a non-empty list of real numbers. You need not check the precondition that the list is non-empty nor the precondition that it contains only reals.

Exercise 7: A safer largest

Rewrite largest using the Husk and Kernel strategy introduced in the reading on preconditions.

For those with extra time

The following exercises will challenge you to extend the problem-solving strategies you’ve learned so far.

Extra 1: Finding skips

(a) Without using index-of, write a procedure, (find-first-skip lst) that takes a list of symbols as a parameter and returns the index of the first instance of the symbol skip in lst, if skip appears in lst. Your procedure may return an error if the symbol skip does not appear in the list.

> (find-first-skip (list 'hop 'skip 'and 'jump))
1
> (find-first-skip (list 'skip 'hop 'jump 'skip 'and 'skip 'again))
0
> (find-first-skip (list 'hop 'to 'work 'jump 'to 'school 'but 'never 'skip 'class))
8

(b) Extend your find-first-skip procedure so that, when the symbol skip is not in the list, the procedure produces #f rather than an error.

> (find-first-skip (list 'hop 'to 'work 'jump 'to 'school 'but 'never 'skip 'class))
8
> (find-first-skip (list 'hop 'and 'jump))
#f

Extra 2: Finding arbitrary values

Write a procedure, (my-index-of val lst) that takes a value and a list of values as its parameters and returns the index of the first instance of val in lst, if the value appears in the list. If the value does not appear, index-of should return #f.

> (my-index-of 'skip (list 'hop 'skip 'and 'jump))
1
> (index-of 5 (list 5 4 3 2 1 2 3 4 5))
0
> (my-index-of "eraser" (list "pencils" "paper" "index cards" "markers" "ball-point pens"))
#f

Extra 3: Riffling lists

Write and document a function (riffle first second) that produces a new list containing alternating elements from the lists first ... second. If one list runs out before the other, then the remaining elements should appear at the end of the new list.

> (riffle (list 'a 'b 'c) (list 'x 'y 'z))
(a x b y c z)
> (riffle (list 'a 'b 'c) (iota 10))
(a 0 b 1 c 2 3 4 5 6 7 8 9)

Extra 4: Difference

The sum procedure adds up all of the elements in a list. Suppose we want to compute the difference of the values in the list. For example, given the list '(a b c d e), we want a - b - c - d - e.

> (difference (list 5))
5
> (difference (list 5 2))
3
> (difference (list 5 2 1))
2
> (difference (list 5 2 1 7))
-5
> (difference (list 5 2 1 7 8))
-13
> (difference (list 5 2 1 7 8 10))
-23

a. Come up with a strategy for implementing difference recursively.

b. Implement that strategy.