This assignment gives you a chance actually write some
challenging Scheme functions. Unless otherwise
specified (or suggested by the examples) you can assume that reasonable
arguments are given to your functions. In other words, you need
not add code to check the arguments provided. Obsessive compulsives
are free to do so, of course.
Getting ready
This assignment assumes that you successfully used the mzscheme
system on the GL machines, or that alternatively, you downloaded
Racket Scheme from the web and have tested it on your own machine.
Your assignment
(1) chop and unchop
You will write a pair of complementary Scheme functions named chop and unchop. Chop takes a proper list L with at least one element and returns a list like L but without it's last element. (recall that a proper list is one that ends in a null.) Unchop takes two arguments, a proper list L (possibly empty) and an arbitrary s-expression X and returns a list like L but with X added as it's last element. Here is an example of their use.
gl3% mzscheme
Welcome to Racket v5.1.3.
> (load "hw6.ss")
> (chop '(1 2 3))
(1 2)
> (chop '(1))
()
> (chop '())
cdr: expects argument of type <pair>; given ()
=== context ===
/Users/Park/Sites/331s13/hw/hw6/hw6.ss:7:0: chop
/opt/racket/collects/racket/private/misc.rkt:85:7
> (unchop '() 100)
(100)
> (unchop '(1 2 3) 'infinity)
(1 2 3 infinity)
Hints: There are several ways to define these functions, some being more efficient than others. For this assignment you need not produce the most efficient solution. Note that lists in Lisp and Scheme are traditional linked lists. One way to access the last element of a list is to traverse the list until you reach an element where the next (cdr) element is the empty list (null). Another way is to use the built in function reverse and take the first element of that. To "remove" an element from the end of a list, you can reverse it, take the cdr, and return the reverse of that. To add an element to the end of the list, you can reverse it, cons the new element onto the result, and then return the reverse of that.
To keep things from being too trivial, you are not allowed
to do:
(append originalList (list lastElement))
I would hope most of you would want to show off a bit, and that solution,
while technically correct, is too simple to allow.
(2) shift-left and shift-right
Write functions
shift-left and shift-right that take a single argument that is assumed to be a list, possibly empty. Shift-left and returns a new list like its
argument but with first element moved to the end of the list. Shift right returns a new list with the last element moved to the front. Here are some examples:
> (shift-left '(1 2 3))
(2 3 1)
> (shift-left '(1))
(1)
> (shift-left '())
()
> (shift-left (shift-left '(1 2 3)))
(3 1 2)
> (shift-right '(1 2 3))
(3 1 2)
> (shift-right '(1))
(1)
> (shift-right '())
()
> (shift-right (shift-right '(a b c)))
(b c a)
(3) zipper?, zip and unzip
Let's define a zipper as a proper list where each element is a list with exactly two elements which can be any expressions. Write a function zipper? that returns #t if its single argument is a zipper and #f if it is not, like so:
> (zipper? '((a 1)(b 2)))
#t
> (zipper? '((foo 100)(bar 2 3)))
#f
> (zipper? '((a 1) b (c 3)))
#f
> (zipper? '((a 1) . 2))
#f
> (zipper? '((a (1)) ((b) 2)))
#t
Next, write a function zip that takes two proper lists (not zippers (although they can be)) and creates a zipper out of them, pairing up elements from the first and second arguments. If the either of the two lists is shorter than the other, use null for the missing elements.
Also write a function unzip that reverses the process, taking a zipper and returning a list of two lists. Some examples should make this clear.
> (zip '(a b c) '(1 2 3))
((a 1) (b 2) (c 3))
> (zip '(a b c) '(1))
((a 1) (b ()) (c ()))
> (zip '(a b) '(1 2 3))
((a 1) (b 2) (() 3))
> (zip '() '())
()
> (unzip '((a 1)(b 2)(c 3)))
((a b c) (1 2 3))
> (unzip '())
(() ())
Testing your Scheme code
You should create a single file named hw6.ss that contains
the definitions of your functions for this problem set.
To help you get started, here is a file with stubs for the functions you have to write. Feel free to add additional functions if you think you need them (you should not, though).
You can test your scheme code using the unit test file hw6test.ss. You can run this from the command line on gl like this
mzscheme -f hw6test.ss
This will run various unit tests and print a report like the following.
linux1[1]% mzscheme -f hw6test.ss
Running chop tests
5 success(es) 0 failure(s) 0 error(s) 5 test(s) run
Running shift tests
12 success(es) 0 failure(s) 0 error(s) 12 test(s) run
Running zip tests
17 success(es) 0 failure(s) 0 error(s) 17 test(s) run
linux1[2]%
What to hand in
Submit to project hw6 a file named hw6.ss with the definition of all of your Scheme functions. |