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

by

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)
        (cond
         ((null? vec1) ())
         (t (cons
             (+ (car vec1) (car vec2))
             (vec+ (cdr vec1)
                   (cdr vec2)))))))
vec+
>>> (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"
vec+

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) ())
        (t
         (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)
          0
          (* n (fact (- n 1)))))
fact
>>> (fact 3)
0
>>> (trace fact)
#!true
>>> (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
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.

Conclusions

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.

References

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
 (begin
 (set! debug (if (car flags) real-debug fake-debug))
 (set! state (car flags))
 state)))))

Corrections

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))
 n)))

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).

 
AAPL
$101.58
Apple Inc.
+0.72
MSFT
$46.52
Microsoft Corpora
-0.24
GOOG
$584.77
Google Inc.
+4.82

MacTech Search:
Community Search:

Software Updates via MacUpdate

BusyCal 2.6 - Powerful calendar app with...
BusyCal is an award-winning desktop calendar that combines personal productivity features for individuals with powerful calendar sharing capabilities for families and workgroups. BusyCal's unique... Read more
Apple iOS 8.0 - The latest version of Ap...
The latest version of iOS can be downloaded through iTunes. Apple iOS 8 comes with big updates to apps you use every day, like Messages and Photos. A whole new way to share content with your family.... Read more
Apple Digital Camera RAW Compatibility 5...
Apple Digital Camera RAW Compatibility update adds RAW image compatibility to Aperture 3 and iPhoto '11. For more information on supported RAW formats, see here.Version 5.07: Adds RAW camera... Read more
Transmit 4.4.7 - Excellent FTP/SFTP clie...
Transmit is an excellent FTP (file transfer protocol), SFTP, S3 (Amazon.com file hosting) and iDisk/WebDAV client that allows you to upload, download, and delete files over the internet. With the... Read more
Macgo Blu-ray Player 2.10.8.1715 - Blu-r...
Macgo Mac Blu-ray Player can bring you the most unforgettable Blu-ray experience on your Mac. Overview Macgo Mac Blu-ray Player can satisfy just about every need you could possibly have in a Blu-ray... Read more
Capture One Pro 8.0.0.433 - RAW workflow...
Capture One Pro 8 is a professional RAW converter offering you ultimate image quality with accurate colors and incredible detail from more than 300 high-end cameras -- straight out of the box. It... Read more
Adobe Acrobat Pro 11.0.09 - Powerful PDF...
Adobe Acrobat allows users to communicate and collaborate more effectively and securely. Unify a wide range of content in a single organized PDF Portfolio. Collaborate through electronic document... Read more
Adobe Reader 11.0.09 - View PDF document...
Adobe Reader allows users to view PDF documents. You may not know what a PDF file is, but you've probably come across one at some point. PDF files are used by companies and even the IRS to... Read more
iFFmpeg 4.6.1 - Convert multimedia files...
iFFmpeg is a graphical front-end for FFmpeg, a command-line tool used to convert multimedia files between formats. The command line instructions can be very hard to master/understand, so iFFmpeg does... Read more
NTFS 11.3.62 - Provides full read and wr...
Paragon NTFS breaks down the barriers between Windows and OS X. Paragon NTFS effectively solves the communication problems between the Mac system and NTFS, providing full read and write access to... Read more

Latest Forum Discussions

See All

Minuum - The Little Keyboard for Big Fin...
Minuum - The Little Keyboard for Big Fingers 1.0 Device: iOS iPhone Category: Utilities Price: $1.99, Version: 1.0 (iTunes) Description: Type faster, see more of your screen, and take control of autocorrect with Minuum: the little... | Read more »
TextExpander 3 + custom keyboard (Utili...
TextExpander 3 + custom keyboard 3.0 Device: iOS Universal Category: Utilities Price: $4.99, Version: 3.0 (iTunes) Description: | Read more »
Swype - Keyboard (Utilities)
Swype - Keyboard 1.0.1411 Device: iOS Universal Category: Utilities Price: $.99, Version: 1.0.1411 (iTunes) Description: Why type when you can Swype? One of the most requested apps for iPhone is finally here. "If Swype itself ever... | Read more »
Joinz (Games)
Joinz 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Joinz is a clever block sliding puzzle game that is easy to play, nice to look at but tricky to master. You will be coming back again... | Read more »
Little World Escape Review
Little World Escape Review By Jordan Minor on September 17th, 2014 Our Rating: :: EARTHBOUNDUniversal App - Designed for iPhone and iPad Little World Escape draws players in with captivating concepts before pushing them away with... | Read more »
Light in the Dark Review
Light in the Dark Review By Nadia Oxford on September 17th, 2014 Our Rating: :: LIGHT 'EM UP UP UPUniversal App - Designed for iPhone and iPad Light in the Dark is an interesting and challenging puzzle game with some amusing bits... | Read more »
ShareFile for iPad is iOS 8-Ready with N...
ShareFile for iPad is iOS 8-Ready with New File-Editi​ng Feature Posted by Jessica Fisher on September 17th, 2014 [ permalink ] | Read more »
Pizo Animals
Pizo Animals By Amy Solomon on September 17th, 2014 Our Rating: :: DELIGHTFUL PUZZLESUniversal App - Designed for iPhone and iPad Pizo Animals is a puzzle app that includes many options adults can choose to customize the experience... | Read more »
ETA for iOS 8 Introduces Today View Exte...
ETA for iOS 8 Introduces Today View Extension and is Having a 50% Off Sale Posted by Jessica Fisher on September 17th, 2014 [ permalink ] | Read more »
Get Ready to Hit the Ice – NHL 2K is Com...
Get Ready to Hit the Ice – NHL 2K is Coming to the App Store Soon Posted by Jessica Fisher on September 17th, 2014 [ permalink ] 2K announced today that they are bringing NHL 2K< | Read more »

Price Scanner via MacPrices.net

Logitech Bluetooth Multi-Device Cross-Platfor...
Logitech has an enviable track record of making some of the best computer keyboards and mice. At least in my estimation, the best freestanding keyboards I’ve ever used have been Logitech units,... Read more
Roundup of Apple refurbished iPad Airs and iP...
Apple is offering Certified Refurbished iPad Airs for up to $140 off MSRP. Apple’s one-year warranty is included with each model, and shipping is free. Stock tends to come and go with some of these... Read more
Sprint offers 16GB iPad mini for $199.99 with...
Sprint is offering 1st generation 16GB iPad minis for $199.99 with a 2-year service agreement. Standard MSRP for this iPad is $429. Their price is the lowest available for this model. Read more
2.5GHz Mac mini remains on sale for $549, sav...
B&H Photo has the 2.5GHz Mac mini on sale for $549.99 including free shipping. That’s $50 off MSRP, and B&H will also include a free copy of Parallels Desktop software. NY sales tax only. Read more
Apple refurbished iMacs available for up to $...
The Apple Store has Apple Certified Refurbished iMacs available for up to $300 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. These are the best prices on... Read more
13″ 2.5GHz MacBook Pro offered for $100 off M...
B&H Photo has the 13″ 2.5GHz MacBook Pro on sale for $999.99 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
Free GIMP Professional Grade Graphics App Ver...
The latest 2.8.14 version of the oddly-named GIMP (acronym for: GNU Image Manipulation Program) open source, high-end image editing and creation alternative to Adobe’s Photoshop and refuge from... Read more
Apple Announces Record Pre-orders for iPhone...
Apple has released metrics showing a record number of first day pre-orders of iPhone 6 and iPhone 6 Plus, with over four million sold in the first 24 hours. Demand for the new iPhones exceeds the... Read more
10% off iPhone 6 and 6 Plus Otterbox cases
Get 10% off on popular Otterbox iPhone 6 and iPhone 6 Plus cases at MacMall through September 19th. Use code OTTERBOX10 to see the discount. Read more
15-inch MacBook Pros on sale for up to $125 o...
Amazon has the new 2014 15″ Retina MacBook Pros on sale for up to $125 off MSRP including free shipping: - 15″ 2.2GHz Retina MacBook Pro: $1899.99 save $100 - 15″ 2.5GHz Retina MacBook Pro: $2374... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.