Lisp Introductory Lab

Part 0: Starting up CLISP and getting started.

1. At a Linux prompt, type clisp and hit Enter.

2. This should 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)

If you have taken CS 217 (Programming Languages), you may have encountered Scheme (depending on the year that you took it). Scheme is similar, but not identical, to Lisp.

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?

(setf mylist '(hey there dude))
(first mylist)
(setf (first mylist) 'bye)
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 I 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:

(setf x (+ 3 2))

3. Save your program by keying ctrl-x followed by ctrl-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

x

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.

8. You can declare "local" variables in LISP via the use of the let function. For example, run the following code:

(let ((a 1) (b 2))
  (setf a 7)
  (setf c (+ a b)))

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

(setf x '(hi there))
(setf y '(hi there))
(setf z 'bye)
(equal x y)
(equal x z)

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:

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

What value is assigned to y? What's happening here? Try changing the value of x in the initial setf statement.

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

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

5. Enter the following code:

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

Can you change the value of 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)
      1
      (* 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.

Example:

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

Part 5: Iteration and printing

1. Enter and load the following function. What does it do? Why?
(setf count 0)
(loop
  (if (equal count 10) (return count) nil)
  (format t "~%Count = ~a." count)
  (setf count (+ count 1)))

Try removing the ~% from the format statement. What does the ~% do? What does the ~a do?

What purpose does (return count) serve?

2. Enter the following code:

(setf x 8)
(if (equal x 8) (progn (setf y 2)
                       (setf z 3))
                (progn (setf y 7)
                       (setf z 9)))

What purpose does progn serve? Where does the return value come from?

Further exercises, due on Friday, 9/17/04.

Use the program hsp to turn in these programs. You should submit one file called hw1.lisp which contains the definitions for the four functions assigned below. Use usual good programming style: indent code appropriately, document your code where hard to read, and include header comments for each function indicating author, purpose of the function, etc. If you need more information on hsp, check out http://webapps.acs.carleton.edu/curricular/cs/resources/hsp/.

1. Create functions num-times-A-iterative and num-times-A-recursive, which are iterative and recursive definitions of a function that takes a list and returns the number of times the symbol A occurs in it. A is not a variable, or a parameter; it is a case-insensitive Lisp symbol, of which you should count how many times it appears. For example:

> (num-times-A-iterative '(2 a hello a elephant A))
3

2. Create functions add-position iterative and add-position-recursive, which are iterative and recursive definitions of a function which takes a list and returns a list of each element plus its position. Positions start at 0. For example:

> (add-position-iterative '(7 5 1 4))
(7 6 3 7)