Debugging in LispWorks

This is a quick introduction explaining how to install LispWorks, and then use it to try out the tutorials on this site. These instructions are for the Mac; some of the details will be slightly different under Windows on the PC.

Note that the programs in this tutorial contain intentional bugs!

Downloading LispWorks

Download the free LispWorks Personal Edition from this page:

LispWorks Personal Edition

Run the installer, and follow the instructions.

The default options install a LispWorks Personal 6.0 folder in your Applications folder:

Double-click the LispWorks Personal icon to run LispWorks.

The toolbar will be displayed, together with a Listener window.

Setting preferences

If you are running LispWorks on the Mac there are two preferences you will probably want to set.

Choose Preferences… from the LispWorks menu.

Select Editor keys are like Mac OS X editors .



. Select The Alt key acts as the Emacs Meta key .



. Click the OK button.

Using the Listener

The Listener is Lisp's interactive command window. You can evaluate an expression, or find the value of a variable, simply by typing it at the > prompt, and pressing Return.

You can also define functions by entering them at the > prompt, followed by Return:

So now you could type:

CL-USER 2 > (average 3 7)

and the Listener will respond with the result:

5

Stopping runaway programs - ctrl cmd comma

When you're programming it's very easy to create an error that causes the program to run for ever, in an infinite loop.

For example, here's an attempt to write a program that prints "Hello" a specified number of times:

(defun print-times (n) (if (< 1 n) nil (progn (print "Hello") (print-times (- n 1)))))

If you test it with:

(print-times 1)

you'll see that the program is stuck in a loop, endlessly printing "Hello".

The solution is to hold down the ctrl and cmd keys, and press the comma key.

Using the Editor

LispWorks also includes an integrated text editor which allows you to enter and edit programs, save programs, and load programs from disk. If you have opened several files you use the Buffers pane to select which file you want to edit in the Text pane.

For example, suppose we are writing a procedure swap to swap the first two elements of a list.

Choose New from the File menu to display a new Editor window with the Text pane selected.



from the menu to display a new window with the pane selected. Enter the following attempt at the swap procedure:

(defun swap (list) (cons (nth list 1) (cons (first list) (rest (rest list)))))

Choose Save from the File menu, and enter a name for the file, such as Exercises.lisp.

To define the swap function you now need to compile it. Assuming that your Editor window isn't wide enough to display the full toolbar:

With the cursor somewhere in the swap function definition in the Editor (or just next to the opening or closing bracket), click the >> symbol at the right-hand end of the Editor window toolbar, and choose Compile from the menu of toolbar icons:

Alternatively, choose Compile Buffer to compile all the definitions in the Editor window.

The compiler messages will be displayed in the Output pane.

Press space to return to the Text pane.

Debugging a procedure

To test the swap procedure we can type an expression into the Listener such as:

(swap '(1 2 3 4))

Because there's an error in the definition the Listener shows an Error message:

The most convenient way to debug a program is to use the interactive debugger.

Click the >> symbol at the right-hand end of the Listener window toolbar, and choose Debug from the menu of toolbar icons:

The Debugger window will be displayed. This shows the history of how the error occurred, called the Backtrace, listing the functions that were called, and let's you see the internal variables (including any arguments) at the point that the error occurred.

Click the triangle next to NTH to show the arguments to the function:

The labels of the arguments, ORIG-N and ORIG-LIST, are a hint that we've got the arguments to nth the wrong way round.

Double-click the SWAP line in the Debugger window.

The Editor window will come to the front, and automatically highlights the part of the swap function that caused the error:

Correct the mistake by changing (nth list 1) to (nth 1 list) , and compile the corrected version of the definition of swap.



to , and compile the corrected version of the definition of swap. Quit from the debugger by clicking >> and choosing Abort from the pop-up menu:

If you try evaluating swap again it should work this time.

Inserting breakpoints

Sometimes the bug you're trying to fix doesn't cause an error, but just causes your procedure to give the wrong result.

For example, here's a first attempt to write last-elt, a procedure to return the last item in a list:

(defun last-elt (list) (let* ((len (length list)) (last (nth len list))) last))

Let's test it in the Listener:

CL-USER > (last-elt '(1 2 3 4)) NIL

That's clearly not what we wanted.

The Debugger is helpful here too. We can insert what's called a breakpoint into the program, and this will cause the debugger to be displayed so we can examine the contents of the variables at that point.

Insert a breakpoint by changing the program to:

(defun last-elt (list) (let* ((len (length list)) (last (nth len list))) (break) last))

Compile the program.



Test it as before by typing (last-elt '(1 2 3 4)) in the Listener.

The breakpoint causes an error called Break.

Select Debug to display the Debugger window, as before.

We can now examine the values of the variables list, len, and last at the breakpoint.

Exit from the debugger by selecting Continue to continue running the procedure from the breakpoint onwards.

What's next?

LispWorks includes a number of other tools to help with debugging Lisp programs, but this tutorial has covered the essentials. For details of the other features refer to the documentation provided with LispWorks Personal Edition.

Please enable JavaScript to view the comments powered by Disqus.

Disqus