However, all isn't lost, because the first restart offered by the debugger will patch things up in just the right way: it will unintern the foo symbol from COMMON-LISP-USER, putting the CL-USER package back to the state it was in before you called foo, allowing the USE-PACKAGE to proceed and allowing for the inherited foo to be available in CL-USER.
This kind of problem can also occur when loading and compiling files. For instance, if you defined a package, MY-APP, for code that was going to use functions with names from the FOOLIB package, but forgot to :use FOOLIB, when you compile the files with an (in-package :my-app) in them, the reader will intern new symbols in MY-APP for the names that were supposed to be read as symbols from FOOLIB. When you try to run the compiled code, you'll get undefined function errors. If you then try to redefine the MY-APP package to :use FOOLIB, you'll get the conflicting symbols error. The solution is the same: select the restart to unintern the conflicting symbols from MY-APP. You'll then need to recompile the code in the MY-APP package so it will refer to the inherited names.
The next gotcha is essentially the reverse of the first gotcha. In this case, you'd have defined a package—again, let's say it's MY-APP—that uses another package, say, FOOLIB. Now you start writing code in the MY-APP package. Although you used FOOLIB in order to be able to refer to the foo function, FOOLIB may export other symbols as well. If you use one of those exported symbols—say, bar—as the name of a function in your own code, Lisp won't complain. Instead, the name of your function will be the symbol exported by FOOLIB, which will clobber the definition of bar from FOOLIB.
This gotcha is more insidious because it doesn't cause an error—from the evaluator's point of view it's just being asked to associate a new function with an old name, something that's perfectly legal. It's suspect only because the code doing the redefining was read with a different value for *PACKAGE* than the name's package. But the evaluator doesn't necessarily know that. However, in most Lisps you'll get an warning about "redefining BAR, originally defined in?". You should heed those warnings. If you clobber a definition from a library, you can restore it by reloading the library code with LOAD.[233]
The last package-related gotcha is, by comparison, quite trivial, but it bites most Lisp programmers at least a few times: you define a package that uses COMMON-LISP and maybe a few libraries. Then at the REPL you change to that package to play around. Then you decide to quit Lisp altogether and try to call (quit). However, quit isn't a name from the COMMON-LISP package—it's defined by the implementation in some implementation-specific package that happens to be used by COMMON-LISP-USER. The solution is simple—change packages back to CL-USER to quit. Or use the SLIME REPL shortcut quit, which will also save you from having to remember that in certain Common Lisp implementations the function to quit is exit, not quit.
You're almost done with your tour of Common Lisp. In the next chapter I'll discuss the details of the extended LOOP macro. After that, the rest of the book is devoted to "practicals": a spam filter, a library for parsing binary files, and various parts of a streaming MP3 server with a Web interface.
22. LOOP for Black Belts
In Chapter 7 I briefly discussed the extended LOOP macro. As I mentioned then, LOOP provides what is essentially a special-purpose language just for writing iteration constructs.
This might seem like a lot of bother—inventing a whole language just for writing loops. But if you think about the ways loops are used in programs, it actually makes a fair bit of sense. Any program of any size at all will contain quite a number of loops. And while they won't all be the same, they won't all be unique either; patterns will emerge, particularly if you include the code immediately preceding and following the loops—patterns of how things are set up for the loop, patterns in what gets done in the loop proper, and patterns in what gets done after the loop. The LOOP language captures these patterns so you can express them directly.
The LOOP macro has a lot of parts—one of the main complaints of LOOP's detractors is that it's too complex. In this chapter, I'll tackle LOOP head on, giving you a systematic tour of the various parts and how they fit together.
The Parts of a LOOP
You can do the following in a LOOP:
• Step variables numerically and over various data structures
• Collect, count, sum, minimize, and maximize values seen while looping
• Execute arbitrary Lisp expressions
• Decide when to terminate the loop
• Conditionally do any of these
Additionally, LOOP provides syntax for the following:
• Creating local variables for use within the loop
• Specifying arbitrary Lisp expressions to run before and after the loop proper
The basic structure of a LOOP is a set of clauses, each of which begins with a loop keyword.[234] How each clause is parsed by the LOOP macro depends on the keyword. Some of the main keywords, which you saw in Chapter 7, are for, collecting, summing, counting, do, and finally.
Iteration Control
Most of the so-called iteration control clauses start with the loop keyword for, or its synonym as,[235] followed by the name of a variable. What follows after the variable name depends on the type of for clause.
The subclauses of a for clause can iterate over the following:
• Ranges of numbers, up or down, by specified intervals
• The individual items of a list
• The cons cells that make up a list
• The elements of a vector, including subtypes such as strings and bit vectors
• The pairs of a hash table
• The symbols in a package
• The results of repeatedly evaluating a given form
A single loop can have multiple for clauses with each clause naming its own variable. When a loop has multiple for clauses, the loop terminates as soon as any for clause reaches its end condition. For instance, the following loop:
(loop
for item in list
for i from 1 to 10
do (something))
233
Some Common Lisp implementations, such as Allegro and SBCL, provide a facility for "locking" the symbols in a particular package so they can be used in defining forms such as DEFUN, DEFVAR, and DEFCLASS only when their home package is the current package.
234
The term KEYWORD package. In fact, any symbol, from any package, with the appropriate name will do; the LOOP macro cares only about their names. Typically, though, they're written with no package qualifier and are thus read (and interned as necessary) in the current package.
235
Because one of the goals of LOOP is to allow loop expressions to be written with a quasi-English syntax, many of the keywords have synonyms that are treated the same by LOOP but allow some freedom to express things in slightly more idiomatic English for different contexts.