CS 313 - Homework 6 - Scheme

Due: Wednesday 4/12 at 11:15am

The purpose of this assignment is to introduce you to the joys of functional programming. You will have to write several functions in Scheme. This is not a group project - you'll have to work by yourself. When you are done, please submit your code for this homework as a single file hw6.scm containing all your functions. as well as plenty of sample output (copy and paste a terminal session) as a single text file hw6-output.txt Upload both files your file via the HW 6 submission page by the beginning of class on Wednesday.

Update: HW 6 testing code is now available

You can download the testing code here or copy it form the lab machines:
% cd cs313/hw6/      // or wherever your scheme file is
% cp ~schar/cs313/hw6/* .
% chmod 755 testhw6     // make executable (might be needed on your Macs)
Once you have copied both my files, run the test script from the command line. Sample run (you'll have to substitute the name of your scheme file):
% ./testhw6
usage: ./testhw6 hw6.scm [problem]

% ./testhw6 hw6.scm 1
(super-reverse ()) = ()  -- OK
(super-reverse (quote (a))) = (a)  -- OK
(super-reverse (quote (a b))) = (b a)  -- OK
(super-reverse (quote (a (b)))) = ((b) a)  -- OK
(super-reverse (quote ((a b) ((c)) (d (e))))) = (((e) d) ((c)) (b a))  -- OK
(super-reverse (quote (a (b (c)) (d e)))) = ((e d) ((c) b) a)  -- OK
======================= 6 of 6 correct ======================
If you leave out the problem number, the script runs all 7 tests.

Like I said in class, make sure that your program doesn't crash my test script. You no longer need to collect or submit sample output. However, before you submit, make sure your code runs through the entire test script without crashing. It should report the total nuber of test cases (out of 50) at the bottom. It's fine if you don't solve all problems, in particular problem 7, but make sure you define at least the requested function(s) with the correct number of arguments, and have them return something, e.g. the empty list or one of the parameters, e.g.,

(define (atom-reverse x) x)
If you need help getting the testing code to work, see me in office hours or email me.

Note that for problem 3a, my test script expects the parameters for member? in the order 'element' first, 'set' second, e.g., (member? 3 '(1 2 4)).

Note that for problem 6, my test script assumes a variable 'empty-bst' has been defined that contains your representation of an empy tree. In case you use an empty list for that, simply add the following line to your code:

(define empty-bst '())

Scheme on the lab machines

A Scheme interpreter called MIT Scheme is installed on the lab machines. To run it, simply type "scheme". (To install Scheme on your own laptop, see the instructions by Ruben linked from the course home page. Don't forget to install "rlwrap" too.)

If you want a better command-line editor (so that the up/down arrow keys cycle through previous commands), use the wrapper program "rlwrap", also installed in the lab, when calling scheme:

schar@abe:~> rlwrap scheme
MIT/GNU Scheme running under GNU/Linux
Type `^C' (control-C) followed by `H' to obtain information about interrupts.

1 ]=>
At the prompt, you can enter Scheme expressions:
1 ]=> (cdr '(a b c))

;Value 1: (b c)
To load a file, use "load" and put the filename in double quotes:
1 ]=> (load "hw6")

;Loading "hw6.scm"
If you get an error, you'll get a different prompt. To get back to the main prompt, type control-G. To exit scheme, type control-D. For an example scheme input file, see my file sample.scm sample.scm in ~schar/cs313/scheme/.

For documentation on Scheme, read Sethi chapters 10.1-3 and 15.6. Also, take a look at the Revised(5) Report on Scheme.

Your assignment:

Implement the following functions. Include sample output for each function! (You can simply cut and paste from a Scheme session into a text file.)
  1. We discussed the function reverse in class. Write a new function super-reverse that recursively reverses a list and all its sublists. For example:
    > (reverse '(a (b c (d)) ((f g) i)))
    (((f g) i) (b c (d)) a)
    > (super-reverse '(a (b c (d)) ((f g) i)))
    ((i (g f)) ((d) c b) a)
    You may wish to define the function atom? that tests if its argument is atomic (i.e., not a pair):
    (define (atom? x)
      (not (pair? x)))
  2. [Sethi #10.9 (b) and (c) on page 419] Provide your own implementations of the built-in functions "list-ref" and "list-tail". Use the names "listRef" and "listTail".
    (listRef mylist n) should return element n of mylist, counting from 0. This can be done recursively as follows: For n = 0, listRef should return the car of the list. Otherwise, listRef should return item (n-1) of the cdr of the list. For example:
    > (listRef '(3 51 9 5) 0)
    > (listRef '(3 51 9 5) 2)
    > (listTail '(3 51 9 5) 2)
    (9 5)
  3. [Sethi #10.7 (a), (b), (c), (d) on page 419] Suppose that sets are implemented as lists, where each element of a set appears exactly once in its list.
    1. Define a function member? that tests whether an element is a member of a set. Use the function equal? to test whether two elements are equal.
    2. Define a function union to construct the union of two sets
    3. Define a function intersection to construct the intersection of two sets
    4. Define a function difference to construct the difference between two sets, i.e., all elements that are in the first set but not in the second set.

  4. [Sethi #10.4 (d) on page 418] Define a function repeats that takes a list and counts the number of adjacent repeated elements, returning a list containing the counts as follows:
    > (repeats '(a b a a a c c))
    ((1 a) (1 b) (3 a) (2 c))
    > (repeats '(a a a a a))
    ((5 a))
    > (repeats '())

  5. [Sethi #10.5 (a) and (b) on page 419] Define tail-recursive functions add and multiply that compute the sum and product of all the elements in a list. For example:
    > (add '(2 4 10 100))
    > (multiply '(2 3 5 7))

  6. Implement a binary search tree in scheme, including functions (insert n bst), (present? n bst), and (traverse bst). Inserting a value should not modify the tree, but rather return a new tree. The function present? should test membership (the name member? is already used in problem 3). The function traverse should return a list of all the values in the tree using an in-order traversal. You can come up with your own representation for BST nodes (hint: think lists). Sample usage:
    > (define t (insert 3 (insert 5 (insert 2 (insert 7 empty-bst)))))
    > (present? 3 t)
    > (present? 4 t)
    > (traverse t)
    (2 3 5 7)

  7. (Almost) optional challenge problem, only worth 2 points out of 50:
    Write a function atom-reverse that is similar to super-reverse except it only reverses the order of the atoms, while maintaining the original list structure. For example:
    > (atom-reverse '(a (b c (d)) ((f g) i)))
    (i (g f (d)) ((c b) a))
    You may want to define helper functions for this one.