Laboratory Exercises For Computer Science 151

An Introduction to Lists in Scheme

An Introduction to Lists in Scheme

Summary: This lab introduces the XEmacs editor and then provides practice with lists in Scheme, including the basic operations (cons, car, cdr), list literals, the empty list, and several common built-in procedures.

Editing Text and Scheme

In the previous lab, you typed commands directly into the Scheme environment, which immediately evaluated and printed the result. While this use of Scheme is quite straightforward, it has at least four disadvantages.

  1. Lines previously typed could not be edited, and only limited editing was possible on the current line.
  2. All program definitions must be retyped every time a program is to be run, as nothing is saved from one use of Scheme to the next.
  3. The results of a computation are not saved, and thus they are difficult to print.
  4. As you work on labs during this course, you may want to take notes and write out explanations for yourself and to hand in.

Using a text editor in conjunction with Scheme can address all of these issues.

Getting Started With XEmacs: We will use the popular XEmacs editor as the basis for our work in this lab.

Steps for this Lab:

  1. Start XEmacs by clicking on the paper icon labeled XE on the bottom control panel.

  2. Resize the window, if necessary, so that it fits nicely on the screen.

Basic XEmacs works as a simple editor, allowing you to open files, edit, save, and print as you might in most word processing packages. For our purposes, however, it will be convenient to set up Xemacs with a split screen. In the bottom window, we will write Scheme and take notes, while we will run Chez Scheme in the top window. Further, when typing Scheme, it is nice to have different elements of the langauge appear in different colors. While this provides a nice environment in which to work, it does require a short setup operation.

Customizing XEmacs for Chez Scheme Programming: Files containing Chez Scheme source code conventionally end in .ss (``Scheme source''). The Scheme mode supplied with XEmacs does not recognize this convention (it assumes .scm instead), but a Chez Scheme programmer can make XEmacs aware of it by revising the XEmacs configuration file, .emacs, in her home directory. The revision need only be made once. Afterwards, XEmacs will automatically be reminded of the .ss convention every time it is started up.

The XEmacs configuration file is actually a short computer program that is executed while XEmacs is starting up, before the window appears. (In fact, this program happens to be written in a language that is a close relative of Scheme -- Emacs Lisp. We won't linger to examine the similarities and differences, though -- the current objective is simply to customize XEmacs to work with Chez Scheme programs.)

  1. Revise your XEmacs configuration file, as follows:

  2. Check whether the customization succeeded.

For much lab work, you will want to write Scheme statements and take notes in the bottom window. After writing a Scheme expression in the bottom window, you can enter the expression directly into Scheme in the top window by moving the mouse immediately after the expression and pressing the Enter key at the far right of your keyboard. (Choosing the Enter key in the middle of your keyboard starts a new line, but does not transfer the preceeding expression to Scheme.)

Check on the interaction between the editing window and Scheme, as follows.

  1. Click your mouse in the bottom editing window, so you can work with the editor.

  2. Type the following line into the editing window:

    
         (+ 2 3)
    
  3. Place the mouse after this expression, and press Enter at the right of the keyboard. You should see the corresponding response 5 in the Scheme window.

    Clarify that the Enter key only enters the information immediately preceeding the mouse. In this line, what happens if the mouse is positioned immediately after the 2? immediately after the 3? on the 3 itself? immediately after the right parenthesis?

  4. Now enter the following lines into the editing window:

    
         (define pi 3.141596535)
         pi
         (* 2 pi 10)
    

    and enter each of these expressions into Scheme. Each time you Enter the expression, you should see a corresponding response in the Scheme window.

Final Notes on XEmacs:
  1. As you are typing, note that when you type a right parenthesis, XEmacs shows you which left parenthesis it matches. This will be particularly helpful when typing longer Scheme programs.

  2. In Scheme mode, pressing the <Tab> key automatically indents the line containing the editing cursor to the correct position. If you use XEmacs to edit Scheme code and follow every carriage return with a tab, you'll always have correctly indented Scheme code.

  3. If you forget to exit from Chez Scheme before closing the XEmacs window in which it is running, XEmacs will remind you by printing the question

    Active processes exist; kill them and exit anyway? (yes or no)
    

    in a pop-up box superimposed on it. If you click on the small rectangle containing the word Yes in response, XEmacs will shut down Chez Scheme for you as it shuts itself down.

  4. While XEmacs is an extremely powerful editor, many common capabilities are highlighted with buttons and menus at the top of window. These menus are analogous to most word processing packages, and thus are not discussed here. Ask the instructor as questions arise. (If something particularly strange seems to be happening, type <Ctrl/g> to stop the processing of a command.)


Introduction to Lists

In Scheme, a list is written by enclosing the elements of the list in parentheses. Here are some simple examples:


   (+ x y)
   (this is a list)
   (sqrt x)
   ()
These lists have 3, 4, 2, and 0 components, respectively. The list () with 0 components also is called the empty list or the null list.

Any or all components of a list can, in turn, be lists:

   (* pi (expt r 2))
   (+ (* x x) (* 3 x) 2)
   (all x (if (human x) (mortal x)))
   ( () )
   ((())) 
   ((()())())
In reviewing the second of these examples, (+ (* x x) (* 3 x) 2) is a list with four components:

   +
   (* x x)
   (* 3 x)
   2
List Extraction Functions: Parts of lists can be extracted by car and cdr: Examples:

   (car '(a b c))          =  a
   (car '((a) b c))        =  (a)
   (car (car '((a) b c)))  =  a
   (car 'a)     error: a is not a list.
   (car '())    error: () is not a pair.

   (cdr '(a b c))          =  (b c)
   (cdr '((a) b c))        =  (b c)
   (cdr (cdr '(a b c)))    =  (c)
   (cdr (car '((a) b c)))  =  ()
   (cdr 'a)     error: a is not a list.
   (cdr '())    error: () is not a pair.
In each of these examples, note that car and cdr are applied to a list which is introduced with a quote. Since parentheses are used both to group data into a list and to call procedures, the Scheme interactive interface needs to see a single quote at the front of a list literal, so that it will treat it as a datum instead of evaluating it.

Since combinations of car and cdr are frequently used, all combinations up to four uses of car and cdr are defined as functions of the form cxxxr:


   (caar x)    = (car (car x))
   (cadr x)    = (car (cdr x))
   (caddr x)   = (car (cdr (cdr x)))
List Constructor Function:
Two basic functions that construct new list structures are the functions cons and list. If y is a list, then we can think of (cons x y) as adding the new element x to the front of the list y.

   (cons 'a '(b c))    =  (a b c)
   (cons 'a '())       =  (a)
   (cons '(a) '(b))    =  ((a) b)
The list function makes a list out of the elements that follow:

   (list 'a 'b 'c 'd)  = (a b c d)
   (list 'a '(b c))    =  (a (b c))
   (list 'a '())       = (a ())
   (list '(a) '(b))    =  ((a) (b))
List Manipulation Functions
append makes a new list consisting of the members of its argument lists. append takes any number of arguments.

   (append '(a) '(b))       =  (a b)
   (append '(a b) '(c d))   =  (a b c d)
   (append '(a) '(b) '(c))  =  (a b c)
reverse makes a new list that is the reverse of the top level of the list given as its argument.

   (reverse '(a b))         =  (b a)
   (reverse '((a b)(c d)))  =  ((c d)(a b))
length returns the number of components in the [top level] of a list.

   (length '(a))      =  1
   (length '(a b))    =  2
   (length '((a b)))  =  1
   (length '(+ (* x x) (* 3 x) 2)) = 4
Steps for this Lab:
  1. Apply the length function to the lists given at the start of this lab. Check that each list has the number of components you expect.

  2. Type the following three expressions into Scheme:
    
       (length 5)
       (length '(+ 2 3))
       (length (+ 2 3))
    
    In each case, explain the result.

  3. Review each of the examples in the introduction involving car and cdr, and type several of these expressions into Scheme. In each case, be sure you understand the result obtained.

  4. Consider the expression (all x (if (human x) (mortal x))). Write Scheme expressions to extract each of the following:
    
       all
       if
       human
    
  5. Write a Scheme expression that creates the list (a b c) out of the individual symbols a, b, and c, using the list function (and the quote function).

  6. Write a Scheme expression that creates the list (a b c) out of the individual symbols a, b, and c, using only the cons, car, and cdr functions (and the quote function).

  7. Write a Scheme expression that creates the list ((a) (b c)) out of the individual symbols a, b, and c. Feel free to use any functions you wish for this part.

  8. Explain what happens when you apply reverse to the lists:
    
       ((a) (b c))
       (+ (* x x) (* 3 x) 2)
    
  9. Evaluate the following slightly tricky forms:
    
    (append '(a b c) '( ))
    (list '(a b c) '( ))
    (cons '(a b c) '( ))
    
    In each case, explain why you received the result that you obtain.
Work to be turned in:


This document is available on the World Wide Web as

http://www.math.grin.edu/~walker/courses/151.sp00/lab-lists.html

created January 22, 1997
last revised August 28, 2000