TweetFollow Us on Twitter

Debugging in Lisp
Volume Number:2
Issue Number:6
Column Tag:AI Applications

Debugging in Lisp

By Andy Cohen, AI Contributing Editor

[Since the last discussion on Macscheme, Semantic Microsystems has updated their product. They are currently shipping version 1.1 which includes access via Macscheme primitives to the Quickdraw routines in ROM. Version 1.1 is also compatible with The Mac+ and HFS. Registered owners of earlier versions can update by sending $20 and their original MacScheme disk to Sematic Microsystems. Additionally, Semantic Microsystems announced the first part of a new development system called Macscheme+Toolsmith. This product includes Pascal-like access to the Toolbox routines in ROM from Macscheme. It also allows the programmer to design an apparently free standing application without the MacScheme environment. A minimized run time system will be required, however, the application and the run time system may be sold without royalties to Sematic Microsystems. Macscheme+ToolSmith will be sold at $250, while Macscheme is still $125 (Which makes us wonder, why $20 for the update?!). We've been pleased with the MacScheme product and the developers' responses to help requests. This month we feature a simple description on using the debugger in MacScheme. - Andy Cohen, A.I. Contributing Editor]

Debugging in Lisp


Anne Hartheimer

Semantic Microsystems, Inc.

Most Lisp systems include good debugging tools, in part because Lisp has traditionally been an interactive, interpreted language. I am going to explain the sorts of debugging tools that are typically provided by Lisp systems, how to take advantage of them and, in particular, how to use the debugging aids provided by the MacScheme Lisp system.

What kinds of debugging help can a system give you? For starters, it can tell you that an error exists. It can also help you find the error that it has told you about. Of course, it can't detect all errors. For example, only you can tell if your program is doing the right thing or generating the output you desire. However, if you know that a program produces the wrong output, or at least questionable output, a debugging tool can help you figure out why. Once you have located the source of the error, Lisp debugging tools can help you fix your buggy program and test it conveniently.

There are several standard debugging tools. Compile-time and run-time error checks discover errors. Inspectors let you examine the scene of the crime. If you suspect that there might be something wrong with a particular procedure, then tracers, steppers, and the ability to insert breakpoints in a program can help you see what is happening as the program is executed. Lastly, editors and incremental compilers can make it easy to modify small parts of your program and move on to the next bug. (One of the reasons Lisp interpreters are popular is that they give you incremental compilation for free.)

MacScheme has all of these tools except a stepper. I'll be using MacScheme in the examples that follow.

Compile-time Checks

Error checks can be performed at compile-time or at run-time. A compiler checks for illegal syntax and some kinds of domain errors. (Compile-time checks for domain errors are usually called type-checks.) In MacScheme, when a compile-time error is detected, it is reported and the system performs a reset. For example, if is a reserved word, so it is not legal syntax to assign to it:

>>> (set! if 3)

ERROR:  Keywords of special forms may
        not be used as variables
(set! if 3)

If a procedure is known to the compiler, then the compiler can make sure it is given the right number of arguments. This is an example of a compile-time domain check.

>>> (cons 3 4 5)

ERROR:  Wrong number of arguments to
        integrable procedure
(cons 3 4 5)

MacScheme, like most Lisps, performs very few compile-time domain checks. This is because Lisp associates types with run-time objects instead of with variables, so compile-time checking is not possible in general. This puts Lisp at a disadvantage compared to Pascal because run-time domain checks are performed only on the pieces of code that are actually executed. If you have a program that contains several branches, you can not be sure that it is free of domain errors until you test each of the branches. In Pascal, on the other hand, many domain errors are caught at compile-time, placing less of a burden on testing. Lisp must make up for this disadvantage by having excellent run-time domain checking.

Run-time Checks

Interpretive Lisp systems excel at run-time error checks. An interpreter will detect undefined variables and domain errors such as passing the wrong number of arguments to a procedure, using a non-procedural object as a procedure, attempting to add two strings, etc. Most systems interrupt execution, print a helpful error message on the screen, and place you inside an inspector so you can examine the context of the error. This is a far cry from a core dump or a bomb window.

The following example is from page 72 of The Little Lisper. vec+ is a function which takes two vectors and returns the vector that is their sum. (The Little Lisper represents vectors as lists instead of using Scheme's built-in vector data type.)

>>> (define vec+
      (lambda (vec1 vec2)
         ((null? vec1) ())
         (t (cons
             (+ (car vec1) (car vec2))
             (vec+ (cdr vec1)
                   (cdr vec2)))))))
>>> (vec+ '(3 4 5) '(1 1 1))
(4 5 6)
>>> (vec+ '(1 2 3 4) '(0 2))

ERROR:  Bad argument to cdr

Entering debugger.  Enter ? for help.

Oops! Let's track down the cause of this error message. We first ask for the name of the procedure in which the error occured.

debug:> i ; "i" means "identify procedure"

So the error occurred in our vec+ routine. Let's look at the code for vec+.

debug:> c ; "c" means "show code"
(lambda (vec1 vec2)
  (cond ((null? vec1) ())
         (cons (+ (car vec1) (car vec2))
               (vec+ (cdr vec1)
                     (cdr vec2))))))

Since the error message told us that cdr was passed a bad argument of (), we should think about the calls to cdr in vec+. (In Scheme, cdr is defined only on non-null lists. When applied to a non-null list, it returns a list consisting of everything in its argument except the first element.) Let's check out the values of vec1 and vec2 since these are the two possible arguments to cdr that could be causing the error.

debug:> a ; "a" means "all variables"

vec1 = (3 4)
vec2 = ()

So vec2 is the problem. Looking more carefully at the code, we can see that we're testing to see if vec1 is null but not vec2. We need to add a test for vec2.

Inside the MacScheme debugger you can find out the name of the procedure in which the error occurred, the arguments that were passed to that procedure, the variables accessible at that point and their values, and the chain of procedures awaiting results. You can move back to the context of any procedure awaiting a result and look at the variables that are accessible to that procedure. You can evaluate arbitrary expressions in the environment of any of the procedures along the chain. You can modify arguments passed to those procedures, and then resume computation. You can modify the values of variables and procedure definitions within the environments of any of the procedures along the chain and resume computation. In addition, you can exit the MacScheme debugger, perform some other computation, and then decide that you want to do additional inspecting of the last bug you encountered. You can reenter the debugger and be back in the state of the most recent error.

Breakpoints, Tracers, and Steppers

Let's shift gears now, and consider the following situation. Suppose your program is producing incorrect output. The traditional approach is to insert print statements in it. The problem with inserting print statements is that it is difficult to know what information to print, and if you print too much the information is unwieldy. It is better to insert breakpoints into your program. In MacScheme, when (break) is evaluated, execution is interrupted and you are placed in the MacScheme debugger. You can now use the full power of the inspector to examine the context of the breakpoint. Instead of having to decide at compile-time what features will be of interest (as you had to do when you debugged by inserting print statements), you get to decide interactively what to look at. For breakpoints to be really useful, your inspector must let you resume the computation. Then you can move on to the next breakpoint that you have set if you decide that things look just fine in the context of the first breakpoint.

It's also useful to be able to induce a break manually to snoop around in computations that seem to be taking a long time or acting weirdly. MacScheme lets you do so by selecting Break from the menu. This interrupts a computation and places you in the MacScheme debugger. When you have finished looking around, you can type an "r" to resume the computation.

If you suspect that a particular routine embedded in your program is producing bad outputs or receiving bad inputs, a convenient way to test your hypothesis is to trace the routine. Whenever a traced routine is called, the MacScheme tracer prints its name and the arguments it was passed. When the routine returns, its name and the value it returns are printed.

>>> (define (fact n)
      (if (zero? n)
          (* n (fact (- n 1)))))
>>> (fact 3)
>>> (trace fact)
>>> (fact 3)
Computing (#<PROCEDURE fact> 3)
 Computing (#<PROCEDURE fact> 2)
  Computing (#<PROCEDURE fact> 1)
   Computing (#<PROCEDURE fact> 0)
   (#<PROCEDURE fact> 0) --> 0
  (#<PROCEDURE fact> 1) --> 0
 (#<PROCEDURE fact> 2) --> 0
(#<PROCEDURE fact> 3) --> 0

Here we see that the recursive calls are passing the correct arguments, but the wrong results are returned.

Once you have determined the problem to be a routine that is receiving good inputs and producing bad outputs, and you have little idea why, you might want to step through the procedure to see what is going wrong. A stepper allows you to view the evaluation of each subexpression of a routine as it is happening. Some steppers let you use the full power of the inspector at each step along the way. You can view a stepper as the ability to insert breakpoints automatically between every expression of your program. A stepper is the one tool I've mentioned that MacScheme doesn't have. To explain why MacScheme does not have a stepper, we must look at the interaction between compiling and debugging.

Interpreters and Compilers

Interpreters are best for development and debugging because they work with the source code, which programmers understand. Compilers turn nice, readable source code into the gobbledygook of machine language--but that machine language sure runs fast. Most Lisp compilers also give up some run-time checking in order to get more speed. One of the main advantages of special-purpose Lisp machines over comparably priced conventional computers is that Lisp machines have special hardware to perform run-time checks very quickly.

MacScheme, like Smalltalk-80, uses a compromise. It compiles to byte code--the machine language for a hypothetical Lisp machine--and then interprets the byte code. This approach gives most of the speed of compiled code together with most of the nice debugging associated with interpreted code. The byte code is also more compact than either native code or source code if the source code is discarded after compilation, but MacScheme normally keeps the source code around to aid in debugging.

Though MacScheme keeps the source code for each user-defined procedure, it does not try to remember the correspondence between individual byte code instructions and source code subexpressions. There just isn't enough memory on a Macintosh to maintain the large tables that would be necessary, which is why MacScheme doesn't have a stepper. Smalltalk-80, on the other hand, does something very clever. Whenever you run its stepper, Smalltalk constructs those tables incrementally, by de-compiling the byte code if necessary.

Texas Instruments' PC Scheme for the IBM PC and TI Professional also uses byte code. Compared to MacScheme, PC Scheme emphasizes speed at some cost to debugging. For example, PC Scheme normally does not retain source code. Because the PC is slower than the Mac and can address less memory, this is a reasonable engineering compromise.


No set of debugging tools can make debugging easy, but they certainly can make it easier, faster, and more fun. We've looked at the help provided by compile-time and run-time error checking, inspectors, breakpoints, tracers and steppers. These tools were first developed for Lisp systems in the 1960's, yet are still hard to find in other languages. Lisp's supportive programming environment is one of the main reasons why so many Lisp programmers are fanatical about their favorite language.


Daniel Friedman and Matthias Felleisen. The Little Lisper. Second Edition. Chicago: Science Research Associates, Inc. (ISBN 0-574-21955-2) 1986.

Adele Goldberg. Smalltalk-80: The Interactive Programming Environment. Menlo-Park: Addison-Wesley Publishing Co. 1984.

How to Turn Off the Debugger

If the automatic placement into the debugger is confusing or it is just a pain to you, try the following procedure sent to us by the folks at Semantic Microsystems:

;;; (debugger #!false) turns off the debugger.
;;; (debugger #!true) turns on the debugger.
;;; (debugger) returns #!true if the debugger is on,
;;; otherwise it returns #!false

(define debugger
 (let ((state #!true)
 (real-debug debug)
 (fake-debug (lambda args (reset))))
 (lambda flags        ; flags is a list of arguments
 (if (null? flags)
 state            ; no arguments
 (set! debug (if (car flags) real-debug fake-debug))
 (set! state (car flags))


A couple of typos from the last column on MacScheme were identified by the author. The first was in one of the code samples using sort. The following is the correct code:

>>> (sort '("Even" "mathematicians" "are" "accustomed" "to" "treating" 
"functions" "as" "underprivileged" "objects")
 (lambda (x y)
 (or (<? (string-length x) (string-length y))
 (string<? x y))))

("as ...)

The second error was in the code defining the procedure make-counter. The code should have included the argument n as follows:

(define make-counter
 (lambda (n)
 (lambda ()
 (set! n (+ n 1))

There was also an error in the third reference. The reference was supposed to read Joseph Stoy's Denotational Semantics of Programming Languages. Our thanks to Will Clinger of the Tektronix Computer Research Laboratory (and also of Semantic Microsystems).


Community Search:
MacTech Search:

Software Updates via MacUpdate

Garmin Express - Manage your Gar...
Garmin Express is your essential tool for managing your Garmin devices. Update maps, golf courses and device software. You can even register your device. Update maps Update software Register your... Read more
Duet - Use your iPad as an exter...
Duet is the first app that allows you to use your iDevice as an extra display for your Mac using the Lightning or 30-pin cable. Note: This app requires a $14.99 iOS companion app. Version Read more
Apple iTunes 12.5.2 - Play Apple Music a...
Apple iTunes lets you organize and stream Apple Music, download and watch video and listen to Podcasts. It can automatically download new music, app, and book purchases across all your devices and... Read more
Pinegrow Web Designer 2.95 - Mockup and...
Pinegrow Web Designer is desktop app that lets you mockup and design webpages faster with multi-page editing, CSS and LESS styling, and smart components for Bootstrap, Foundation, Angular JS, and... Read more
jAlbum Pro 13.6 - Organize your digital...
jAlbum Pro has all the features you love in jAlbum, but comes with a commercial license. You can create gorgeous custom photo galleries for the Web without writing a line of code! Beginner-friendly... Read more
jAlbum 13.6 - Create custom photo galler...
With jAlbum, you can create gorgeous custom photo galleries for the Web without writing a line of code! Beginner-friendly, with pro results - Simply drag and drop photos into groups, choose a design... Read more
TextMate 2.0-beta.12.26 - Code/markup ed...
TextMate is a versatile plain text editor with a unique and innovative feature set which caused it to win an Apple Design Award for Best Mac OS X Developer Tool in August 2006. A rapidly growing... Read more
VMware Fusion 8.5.1 - Run Windows apps a...
VMware Fusion 8 and Fusion 8 Pro--the latest versions of its virtualization software for running Windows on a Mac without rebooting--include full support for Windows 10, OS X El Capitan, and the... Read more
Apple Final Cut Pro X 10.3 - Professiona...
Apple Final Cut Pro X is a professional video editing solution.Completely redesigned from the ground up, Final Cut Pro adds extraordinary speed, quality, and flexibility to every part of the post-... Read more
Civilization VI 1.0.0 - Next iteration o...
Sid Meier’s Civilization VI is the next entry in the popular Civilization franchise. Originally created by legendary game designer Sid Meier, Civilization is a strategy game in which you attempt to... Read more

Latest Forum Discussions

See All

Plants vs. Zombies Heroes guide: How to...
Plants vs. Zombies Heroes might look cute and cuddly, but it's actually a very complex deck builder that requires a lot of time to master. While there's a bit of a learning curve, it's easy for people of any skill level to have fun with the game. | Read more »
Roofbot: Puzzler On The Roof (Games)
Roofbot: Puzzler On The Roof 1.0.2 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.2 (iTunes) Description: Guide Roofie through gorgeous, meditative rooftops and try to get the right color energy balls into the... | Read more »
The 4 best food delivery apps
As the temperatures continue to drop, so does the motivation to venture outside. Sometimes you still want to eat a nice meal from that sushi place down the road though. Thankfully in these trying times, there are a number of fine food delivery... | Read more »
Toca Life: Farm (Education)
Toca Life: Farm 1.0 Device: iOS Universal Category: Education Price: $2.99, Version: 1.0 (iTunes) Description: Work and play the farmer's way! Milk your cow, gather eggs from your hens and raise your crops. Have a picnic, play the... | Read more »
The Lost Shield (Games)
The Lost Shield 1.0.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.0 (iTunes) Description: The Lost shield is a brick break/adventure game. You play as a hero who must return a powerful but dangerous magic shield... | Read more »
The Forgotten Room (Games)
The Forgotten Room 1.0.1 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.1 (iTunes) Description: Play as paranormal investigator John “Buster of Ghosts” Murr as he explores yet another mysteriously creepy house. This... | Read more »
5 Halloween mobile games for wimps
If you're anything like me, horror games are a great way to have nightly nightmares for the next decade or three. They're off limits, but perhaps you want to get in on the Halloween celebrations in some way. Fortunately not all Halloween themed... | Read more »
The 5 scariest mobile games
It's the most wonderful time of the year for people who enjoy scaring themselves silly with haunted houses, movies, video games, and what have you. Mobile might not be the first platform you'd turn to for quality scares, but rest assured there are... | Read more »
Lifeline: Flatline (Games)
Lifeline: Flatline 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: The Lifeline series takes a terrifying turn in this interactive horror experience. Every decision you make could help... | Read more »
Game of Dice is now available on Faceboo...
After celebrating its anniversary in style with a brand new update, there’s even more excitement in store for Game of Dice has after just being launched on Facebook Gameroom. A relatively new platform, Facebook Gameroom has been designed for PC... | Read more »

Price Scanner via

WaterField Unveils Syde MacBook Pro Touch Bar...
The new WaterField Designs Syde Case for Apple’s new MacBook Pro Touch Bar combines the top-notch laptop protection of a sleeve with the functionality and handsome look of an over-the-shoulder or... Read more
Apple Unveils Redesigned MacBook Pro With Tou...
October 27, 2016 – Apple today introduced the thinnest and lightest MacBook Pro yet, along with a new interface innovation that replaces the traditional row of function keys with a Retina-quality... Read more
Apple Unveils New TV App for Apple TV, iPhone...
October 27, 2016 – Apple today introduced a new TV app, offering a unified experience for discovering and accessing TV shows and movies from multiple apps on Apple TV, iPhone and iPad. The TV app... Read more
Price drops on select refurbished 2015 13″ Re...
Apple dropped prices on select Certified Refurbished 2015 13″ Retina MacBook Pros by as much as $90. An Apple one-year warranty is included with each model, and shipping is free: - 13″ 2.7GHz/256GB... Read more
Apple reveals new next-generation 15″ and 13″...
Apple today revealed their next-generation 15″ and 13″ MacBook Pros. The new models are thinner and lighter than before with a new aluminum design featuring an enhanced keyboard with retina, multi-... Read more
Worldwide Smartphone Shipments Up 1.0% Year o...
According to preliminary results from the International Data Corporation (IDC) Worldwide Quarterly Mobile Phone Tracker, vendors shipped a total of 362.9 million smartphones worldwide in the third... Read more
TuneBand Arm Band For iPhone 7 and 7 Plus Rel...
Grantwood Technology has added the TuneBand for iPhone 7 and 7 Plus to its smartphone armband series. The TuneBand provides a lightweight and comfortable way to wear the iPhone while running,... Read more
1.4GHz Mac mini on sale for $449, save $50
Adorama has the 1.4GHz Mac mini on sale for $50 off MSRP including free shipping plus NY & NJ sales tax only: - 1.4GHz Mac mini (Apple sku# MGEM2LL/A): $449 $50 off MSRP To purchase a mini at... Read more
21-inch 1.6GHz iMac on sale for $999, save $1...
B&H has the 21″ 1.6GHz Apple iMac on sale for $999 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
Macs’ Superior Enterprise Deployment Cost Eco...
IBM’s debunking of conventional wisdom and popular mythology about the relative cost of using Apple Mac computers as opposed to PCs running Microsoft Windows at the sixth annual Jamf Nation User... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Software Engineering Intern: UI Applications...
Job Summary Apple is currently seeking enthusiastic interns who can work full-time for a minimum of 12-weeks between Fall 2015 and Summer 2016. Our software Read more
Security Data Analyst - *Apple* Information...
…data sources need to be collected to allow Information Security to better protect Apple employees and customers from a wide range of threats.Act as the subject Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Solutions Consultant - Apple (United...
# Apple Solutions Consultant Job Number: 52812872 Houston, Texas, United States Posted: Oct. 18, 2016 Weekly Hours: 40.00 **Job Summary** As an Apple Solutions Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.