[Instructions] [Search] [Current] [Syllabus] [Links] [Handouts] [Outlines] [Assignments] [Labs]

**Assigned**: Friday, February 5, 1999

**Due**: Friday, February 12, 1999

*All of your coding for this assignment should be done in Scheme.
Make sure to turn in not just your code, but also examples that document
the testing of your code.*

The purpose of this assignment is to get you accustomed to a number of issues in Scheme programming, particularly higher-order functions and delayed evaluation. Problem A is also intended to help you think about testing and design issues.

As you may have noted from your career as a student of computer science, it is essential to develop good and comprehensive testing routines for your attempted implementations of algorithms, using both black-box (we know what it's supposed to do, but not how it does it) and white-box (we also know how it does it, and want to make sure we exercise the various parts) techniques. In the case of sorting routines, it is particularly important to develop reasonably comprehensive testing routines. Here is a reasonable black-box test routine (although perhaps too slow), written in a generic imperative language

for each list size from 0 tosome reasonable size(e.g., 8) for each kind of list of that size generate a sample list of that kind and size for each permutation of that list make sure the sorting mechanism works

What ``kinds'' of lists do we want? At least four kinds: one kind of list has no duplicates. Since we're building every permutation, it seems reasonable to simply generate a sequence of numbers (possibly starting with a negative number and ending with a positive one so that we also test positive/negative problems). A second kind of list has all the same value to ensure that numbers aren't lost. A final kind of list is of a mixed form: some duplicates, some differences.

Your goal will be to translate these ideas into a comprehensive sort
testing predicate, *(sorts? function)* that takes a sorting
function as a parameter and returns true (`#t`

) if the
parameter seems to be a correct sorting routine (or at least passes a
relatively comprehensive suite of tests and false (`#f`

) if
it fails some test.

Since there are lots of permutations of typical lists, you should only use 4 or 5 as the ``reasonable size'' in this case. In practice, we'd use much larger sizes.

**A.1. Generating Sequences**

Write a Scheme function `(nints n start)`

that generates a
list of
`n`

successive integers starting with `start`

.
For example, `(nints 4 -2)`

would produce the list
`(-2 -1 0 1)`

.

**A.2. Generating Copies**

Write a Scheme function `(ncopies n val)`

that generates a
list of `n`

copies of `val`

. For example,
`(ncopies 4 3)`

would produce `(3 3 3 3)`

.

**A.3. Generating Compound Sequences**

Write a Scheme function that generates lists which have some of the criteria given above. That is, they should include both different numbers and copies of some number (as long as the list has at least three elements).

**A.4. Generating Permutations**

Write a recursive Scheme function, `(permutations lst)`

, that
generates
a list of all the permutations of `lst`

. For example,
`(permutations '(1 2 3))`

should produce something like

( (1 2 3) (2 1 3) (2 3 1) (1 3 2) (3 1 2) (3 2 1) )

Chat with me if you need some ideas on how to do this recursively.

**A.5. Developing a Testing Predicate**

Using the pieces developed above, develop a predicate,
`(sorts? fun)`

that returns true if `fun`

appears to sort lists and false otherwise.

**A.6. Developing a Quicksort Function**

Write a function, `(quicksort lst)`

, that computes a sorted
version of `lst`

using the quicksort algorithm. Run your
testing predicate on your sorting routine and report the results.

**A.7. Developing a Mergesort Function**

Write a function, `(mergesortlst)`

, that computes a sorted
version of `lst`

using the mergesort algorithm. Run your
testing predicate on your sorting routine and report the results.

**A.8. Developing an Insertion Sort Function**

Write a function, `(itsort lst)`

, that computes a sorted
version of `lst`

using the insertion sort algorithm. Run your
testing predicate on your sorting routine and report the results.

As we've seen, Scheme generally performs a form of *eager*
evaluation: before calling a function on arguments, it evaluates the
arguments. Some time ago, a number of computer science researchers
suggested that one use *lazy* evaluation, in which one delays
evaluation of an expression as long as possible.

Scheme provides a few built-in functions to support this type of evaluation. However, it is also possible to support delayed evaluation using lambda expressions. Consider the lambda expression

(lambda () (+ a (* b c)))

This indicates "when this function is applied" (to nothing), multiply b and c and then add a". To apply this function, we simply compute an expression with it. For example,

> (define a 2) > (define b 3) > (define c 4) > (define fun (lambda () (+ a (* b c)))) > fun#<procedure fun>> (fun)14> (define a 100) > (fun)112> (define (foo a) (+ a (fun))) > (foo 1)113

Let's consider how we might use this in building lists. Suppose we
wanted to build a list of four items and only used the forth. It
would obviously be a waste of computation power to compute all four
items in advance. Hence, we might encapsulate each in a lambda
expression and then only extract them when necessary. In fact, if
we were to take this idea to extremes, we might not even want to build
anything but the first `cons`

cell (leaving the construction
of the remaining ones to "on demand").

Why might this be useful? Well, it provides a different form of
program modularity. Consider the functions `(listn n)`

which lists the first `n`

integers and
`(nprimes n)`

which lists the first `n`

primes.
Good program design suggests that we should extract out any common
features of these two functions. What is common? Getting the first
`n`

elements in a sequence. We could define then define
`(firstn n lis)`

as

(define (firstn n lis) (if (= n 0) nil (cons (car lis) (firstn (- n 1) (cdr lis)))))

Unfortunately, if we choose to do this, we need a way to build lists of
unknown length. In effect, we need to delay construction of the list
until the parts of the list are needed (or demanded). We'll call lists
with encapsulated cars and cdrs *encapsulated lists*.

**B.1. Unencapsulation**

Write a function, `(demand encapsulated)`

, that extracts
an encapsulated value from a lambda abstraction. For example,

(demand (lambda () (+ 2 3)))

should return 5.

**B.2. List Unencapsulation**

Write functions `demandcar`

and `demandcdr`

, that
extract the actual `car`

and `cdr`

of an encapulsated
list. For example,

> (define ls (cons (lambda () (display 'a) (newline) (+ 2 3)) (lambda () (cons (lambda () (display 'b) (newline) (* 3 4)) (lambda () nil))))) > (demandcdr (demandcdr ls))()> (demandcar ls)a5> (demandcar (demandcdr ls))b12

**B.3. Infinite Lists**

Write a function, `(intsfrom n)`

, that creates an encapsulated
list of all the integers from n to infinity.

**B.4. firstn, revisited**

Create an appropriate variant of the `firstn`

function above
that works with encapsulated lists. Use it to test your
`intsfrom`

function.
For example,

> (firstn 3 (intsfrom 5))(5 6 7)

**B.5. Filtering**

Write a function, `(filter pred encaplst)`

that, given a
predicate and an encapsulated list, creates a new encapsulated list
which contains only the members of the parameter meeting the predicate.

**B.6. More Filtering**

Using `filter`

, write a function ```
(filterOutMultiples n
encaplst)
```

that returns an encapsulated list containing only the
elements of the encapsulated list that are not multiples of n.

**B.7. Primes**

Using your other methods from this problem, write a function
`primes`

that returns an encapsulated list of the
prime numbers. You will most likely want to use the Sieve of
Eratothenes: start with the numbers starting with 2. Repeatedly
take off the first number (that's a prime) and then filter out
multiples of that number.

**History**

- Created April 1998 for CSC302 98S.
- Updated February 5, 1999, for Grinnell College's CSC302 99S. Removed a problem on continuations. Added some steps to the problem on infinite lists. Added some notes on problem A.

[Instructions] [Search] [Current] [Syllabus] [Links] [Handouts] [Outlines] [Assignments] [Labs]

**Disclaimer** Often, these pages were created ``on the fly'' with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.

This page may be found at http://www.math.grin.edu/~rebelsky/Courses/CS302/99S/Assignments/assign.02.html

Source text last modified Fri Feb 12 07:35:19 1999.

This page generated on Fri Feb 12 07:37:18 1999 by SiteWeaver. Validate this page's HTML.

Contact our webmaster at rebelsky@math.grin.edu