[Source: http://www.mathcs.carleton.edu/faculty/dmusican/cs327f04/lab1.html, modified by P. H. Roosen-Runge, September 2005, for COSC3401A, Fall 2005, York University.]

Lisp Introductory Lab

Part 0: Starting up CLISP and getting started.

1. At an indigo prompt, type clisp -q and hit [Enter].

2. This will start up the CLISP environment. At the CLISP prompt, type

(+ 3 4)

and hit [Enter].

3. This should add 3 to 4. In Lisp, + is a function. To make a function call in Lisp, you place the name of the function and its arguments, separated by spaces, inside parentheses. This takes a little getting used to! In C++ and Java, function calls look something like this:

function(arg1, arg2, arg3);

In Lisp, function calls look like this:

(function arg1 arg2 arg3)

Part 1: Basic Lisp Primitives

1. At the CLISP prompt, enter the following:

(first '(apple orange pineapple))
(rest '(apple orange pineapple))
(first (apple orange pineapple))
If you get stuck at a "break" prompt, you can type quit to get back to the high-level CLISP prompt.

What do first and rest do? Why is the single quote necessary? What does it do?

2. Write sequences of first and rest that will pick the symbol pear out of the following expressions:

(apple orange pear grapefruit)
(((apple) (orange) (pear) (grapefruit)))
(apple (orange) ((pear)) (((grapefruit))))

3. Execute the following statements. What do the functions cons, append, and list do?

; This is a comment, by the way!
(cons 'x '(1 2))
(cons '(1 5) '(2 3))
(append '(1) '(2 3))
(append '(1 5) '(2 3))
(list '1 '2 '3 '(4 5))

4. Execute the following code. What results do you get, and why?

(DEFUN mylist() '(hey there dude))
(DEFUN mylist2() (list 'bye (rest (mylist))))

5. Execute the following code. What do length and reverse do?

(length '(plato socrates aristotle))
(reverse '(plato socrates aristotle))

6. Enter the following code.

(nth 1 mylist)

What does nth do?

Part 2: Editing code and defining functions

Clearly, you don't want to keep entering all your code into the CLISP prompt. You can write functions in a text editor, then load them into CLISP. You can use any editor you want, but we strongly recommend learning emacs. It's the right tool for the right job, especially when programming in LISP.

1. From the terminal window, type

emacs part2.lisp

This will open up an emacs window to edit the program part2.lisp.

2. Type in some Lisp code:

(DEFUN x (+ 2 3))

3. Save your program by keying ctrl-x followed by ctrl-s [in Emacs documentation, this is written C-X C-S], or going to the menu bar and selecting Files, followed by Save Buffer.

4. In your CLISP window, type

(load "part2.lisp")

This will execute whatever code is in your file. In CLISP, type


at the prompt. You should see a 5 in response.

5. Remove the code that you currently have in part2.lisp, and instead type or copy in the following. Hit the tab key on each line so that emacs will automatically indent your code for you. Save when done.

(defun both-ends (whole-list)
  (cons (first whole-list)
        (last whole-list)))

6. In CLISP, load in the function. Then type

(both-ends '(breakfast lunch dinner snack pizza))

What does the function both-ends do? How? Where is the name of the function? Where are the parameters of the function? How does it determine which value to return?

7. Define rotate-left, a function that takes a list as its argument and returns a new list in which the former first element becomes the last.

After executing this code, what are the values of a, b, and c? Why?

Part 3: Conditionals

Lisp has different predicates for testing equality.

1. At the CLISP prompt, type

(equal 'bye '(hi there))
(equal '(hi there) '(hi there))

(eq 'hi 'hi)
(eq '(hi there) '(hi there))

What kind of responses do you get? Why?

2. At the CLISP prompt, type

(equal 4 4.0)
(= 4 4.0)
(= x y)

What kind of responses do you get?

In short: = only works on numbers, but will return the correct answer if the types are different. equal will work on all types, but distinguishes between numbers of different types as different.

3. Define the function divisible-by which takes two numeric arguments, and determines if the first is divisible by the second. For example, (divisible-by 10 2) should return T, while (divisible-by 10 3) should return NIL. Use the built in function rem that takes two integer arguments and returns the remainder when the first argument is divided by the second.

4. Enter the following code:

(DEFUN x() 5)
(if (= (x) 3)
    (DEFUN y() 9)
    (DEFUN y() 10))

What value is returned by (y)? What's happening here?

The following code achieves the same purpose. Why does it work?

(DEFUN x() 5)
(DEFUN y() (if (= (x) 3) 9 10))

5. Enter the following code:

(DEFUN x() 8)
(DEFUN y() (cond ((= (x) 3) (+ 3 8))
              ((= (x) 8) 12)
              (t (* 6 3))))

Can you change the value returned by x to get different values of y? What does each portion of the cond function do?

Part 4: Recursion

1. Enter and load the following function. What does it do? Why?
(defun mystery (m n)
  (if (zerop n)
      (* m (mystery m (- n 1)))))

Note that there is no "return" statement here, as you would find in a similar function in Java. Why? How is the return value determined in the above function?

2. Write a function, keep-first-n, that returns a list of the first n elements in a list. You may assume that there are at least n elements.


> (keep-first-n 3 '(a b c d e f g h i))
(A B C)