This lab is also available in PDF.
Summary: In this laboratory, you will begin your experimentations with recursion by (1) considering some pre-defined recursive procedures and (2) designing your own recursive procedures.
a. Reflect on the key aspects of recursion.
b. Start DrScheme.
Here are the two versions of
sum as given in
the reading on recursion.
;;; Procedures: ;;; sum ;;; new-sum ;;; Parameters: ;;; numbers, a list of numbers. ;;; Purpose: ;;; Find the sum of the elements of a given list of numbers ;;; Produces: ;;; total, a number. ;;; Preconditions: ;;; All the elements of numbers must be numbers. ;;; Postcondition: ;;; total is the result of adding together all of the elements of ls. ;;; If all the values in numbers are exact, total is exact. ;;; If any values in numbers are inexact, total is inexact. (define sum (lambda (numbers) (if (null? numbers) 0 (+ (car numbers) (sum (cdr numbers)))))) (define new-sum (lambda (numbers) (new-sum-helper 0 numbers))) ;;; Procedure: ;;; new-sum-helper ;;; Parameters: ;;; sum-so-far, a number. ;;; remaining, a list of numbers. ;;; Purpose: ;;; Add sum-so-far to the sum of the elements of a given list of numbers ;;; Produces: ;;; total, a number. ;;; Preconditions: ;;; All the elements of remaining must be numbers. ;;; sum-so-far must be a number. ;;; Postcondition: ;;; total is the result of adding together sum-so-far and all of the ;;; elements of remaining. ;;; If both sum-so-far and all the values in remaining are exact, ;;; total is exact. ;;; If either sum-so-far or any values in remaining are inexact, ;;; total is inexact. (define new-sum-helper (lambda (sum-so-far remaining) (if (null? remaining) sum-so-far (new-sum-helper (+ sum-so-far (car remaining)) (cdr remaining)))))
a. Verify experimentally that they work.
b. Which version do you prefer? Why?
c. Here's an alternative definition of
(define newer-sum (lambda (numbers) (new-sum-helper (car numbers) (cdr numbers))))
Is it superior or inferior to the previous definition? Why?
Here is a variant of the
largest-of-list procedure given in
the reading on recursion.
;;; Procedures: ;;; largest-of-list ;;; Parameters: ;;; numbers, a list of real numbers. ;;; Purpose: ;;; Find the largest element of a given list of real numbers ;;; Produces: ;;; largest, a real number. ;;; Preconditions: ;;; numbers is not empty. ;;; All the values in numbers are real numbers. That is, numbers ;;; contains only numbers, and none of those numbers are complex. ;;; Postconditions: ;;; largest is an element of numbers (and, by implication, is real). ;;; largest is greater than or equal to every element of numbers. (define largest-of-list (lambda (numbers) ; If the list has only one element (if (null? (cdr numbers)) ; Use that one element (car numbers) ; Otherwise, take the greater of ; (a) the first element of the list ; (b) the largest remaining element (max (car numbers) (largest-of-list (cdr numbers))))))
Here's an alternative version, based on a design from some students in a Spring 2003 session of CSC 151. Many students in the class participated in the design, but Andy Cook and Brett McMillian provided the key ideas. Sam Rebelsky wrote the extra documentation.
(define new-largest-of-list (lambda (numbers ) (new-largest-of-list-helper numbers (max (car numbers) (cadr numbers)) 2))) ;;; Procedure: ;;; new-largest-of-list-helper ;;; Parameters: ;;; numbers, a list of numbers ;;; largest-so-far, a number ;;; position, an integer ;;; Purpose: ;;; Find the largest value in a sublist of numbers. ;;; Produces: ;;; largest, a number ;;; Preconditions: ;;; position >= 0 [Unverified] ;;; position <= (length numbers) [Unverified] ;;; numbers contains only real numbers (no complex numbers). [Unverified] ;;; largest-so-far is a real number (not complex). [Unverified] ;;; Postconditions: ;;; largest is the largest of (a) largest-so-far and (b) elements ;;; position .. last of numbers. (See largest-of-list for what ;;; it means to be largest.) (define new-largest-of-list-helper (lambda (numbers largest-so-far position) ; If we run off the end of the list, use the largest-so-far (if (>= position (length numbers)) largest-so-far ; Otherwise, update your guess and continue (new-largest-of-list-helper numbers (max largest-so-far (list-ref numbers position)) (+ position 1)))))
a. Which version do you prefer? Why?
b. Experiment with the two versions to verify that they work as advertised.
c. There's at least one kind of list for which one of the procedures works and one of the procedures doesn't. Can you tell which one?
Here's yet another version of
largest-of-list, one based
(define newer-largest-of-list (lambda (numbers) (newer-largest-of-list-helper (car numbers) (cdr numbers)))) (define newer-largest-of-list-helper (lambda (largest-so-far remaining-numbers) ; If no elements remain ... (if (null? remaining-numbers) ; Use the largest value seen so far largest-so-far ; Otherwise, update the guess using the next element ; and continue (newer-largest-of-list-helper (max largest-so-far (car remaining-numbers)) (cdr remaining-numbers)))))
a. Verify experimentally that this procedure works correctly.
b. You may find it helpful to
Add the following two lines to
new-largest-of-list-helper (right before the outermost
(display (list 'new-largest-of-list-helper numbers largest-so-far position)) (newline)
Add the following two lines to
newer-largest-of-list-helper (right before the outermost
(display (list 'newer-largest-of-list-helper largest-so-far remaining-numbers)) (newline)
What effect does this change have?
c. How is
newer-largest-of-list-helper procedure similar to
new-largest-of-list-helper? How is it different? What are the advantages and disadvantages of the changes?
c. Which of the three versions do you prefer? Why?
As some students note, there is no need for us to define any of the
largest-of-list, since Scheme gives us
an equivalent procedure in
max. While that complaint has
a glimmer of validity, it is, in fact, useful to figure out how to write
many of the built-in Scheme procedures. One reason is that learning
the structure of those procedures makes it easier to write other, similar,
Consider the problem of finding one of the longest strings in a list
of strings, a string whose length is at least as large as the length
of each of the other strings. (We say
one of the longest strings
because more than one string may have the same length.) For example,
> (longest-string-in-list (list "zebras" "have" "stripes") "stripes" > (longest-string-in-list (list "stripes" "often" "appear" "on" "zebras") "stripes" > (longest-string-in-list (list "this" "is" "a" "silly" "list")) "silly" > (longest-string-in-list (list "this" "is" "a" "long" "list")) "this" ; or "list", or although it seems unlikely, "long"
We might document this procedure as follows:
;;; Procedure: ;;; longest-string-in-list ;;; Parameters: ;;; los, a nonempty list of strings ;;; Purpose: ;;; Finds a longest string in los. ;;; Produces: ;;; longest, a string ;;; Preconditions: ;;; (none) ;;; Postconditions: ;;; For any string in los, (string-length longest) >= (string-length str) . ;;; longest is an element of los. ;;; Problems: ;;; los may contain many strings that meet the postconditions. We do ;;; not specify which of those strings is returned.
Using any of the patterns of
Define and test a Scheme procedure,
that takes a list of numbers as its argument and returns the result of
multiplying them all together. For example,
> (product (list 3 5 8)) 120 > (product (list 1 2 3 4 5 0)) 0
should not be 0. It should be the identity for multiplication,
(sum null) is the identity for addition.
Write a Scheme procedure,
that, given a list of numbers (including both negative and positive
numbers), returns the value closest to zero in the list.
Hint: Think about how, given two numbers, you determine which is closer to zero.
Hint: Think about how this problem is similar to a problem or problems we've solved before.
Define and test a Scheme procedure,
values), that takes a list of numbers as its argument and
returns a list of their squares.
> (square-each-element (list -7 3 12 0 4/5)) (49 9 144 0 16/25)
Hint: For the base case, consider what the procedure should return when given a null list; for the other case, separate the car and the cdr of the given list and consider how to operate on them so as to construct the desired result.
If you find that you finish this laboratory early, you can start the next laboratory on list recursion.
I usually create these pages
on the fly, which means that I rarely
proofread them and they may contain bad grammar and incorrect details.
It also means that I tend to update them regularly (see the history for
more details). Feel free to contact me with any suggestions for changes.
This document was generated by
Siteweaver on Thu Nov 30 21:43:09 2006.
The source to the document was last modified on Mon Sep 11 12:33:13 2006.
This document may be found at
You may wish to validate this document's HTML ; ;Samuel A. Rebelsky, firstname.lastname@example.org
http://creativecommons.org/licenses/by-nc/2.5/or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.