In this chapter, you'll learn how to find your way around Common Lisp without resorting so often to the manuals. (You do read the fine manuals, don't you?)
Oh, there's one thing you should keep in mind while you're reading this chapter: all of these tools work equally well for the built-in functionality of your Lisp system and for all of the Lisp programs that you write.
Common Lisp defines 978 symbols. Whatever implementation you use probably defines hundreds of additional symbols for language extensions, additional libraries, a graphical user interface, etc. Are you going to remember the names of all these symbols? Not likely...
What you can do is to remember part of the name. This is
pretty easy, because the language and library designers have a
limited memory (just like you and me) and they tend to name related
objects with similar names. So, most of the mapping functions (see
Chapter 12) will have MAP
in their names, the GUI library will probably have
WINDOW
in the names of all the functions, macros, and
variables having something to do with windows, and so on.
Once you have a good guess at a part of a name, you can find
all of the matching names by using a very handy tool named
APROPOS
.
? (apropos "MAP" :cl) MAP, Def: FUNCTION MAP-INTO, Def: FUNCTION MAPC, Def: FUNCTION MAPCAN, Def: FUNCTION MAPCAR, Def: FUNCTION MAPCON, Def: FUNCTION MAPHASH, Def: FUNCTION MAPL, Def: FUNCTION MAPLIST, Def: FUNCTION
APROPOS
expects a string or a symbol -- this
provides the fragment of the name that you'd like to find. An
optional second argument designates a package; use it if you'd like
to limit your search to the symbols in a particular package. The
package designator can be a string or symbol matching the name or
nickname of a package (see Chapter 3,
Lesson 10), or it can be the package object itself. If you omit
the package designator, then APROPOS
will search for
symbols in all packages.
Your Lisp implementation may produce output that looks somewhat different from that shown here. Generally, you'll see the symbol names listed with a very brief description of the global object named by the symbol.
Here's an example of the output from APROPOS
on my
Lisp system when I search without a package designator:
? (apropos "SEQUENCE") TOOLS::BROWSER-SEQUENCE-TABLE CCL::CHECK-SEQUENCE-BOUNDS, Def: FUNCTION ITERATE::CHECK-SEQUENCE-KEYWORDS, Def: FUNCTION TOOLS::CLASS-BROWSER-SEQUENCE-TABLE ITERATE::CLAUSE-FOR-IN-SEQUENCE-0, Def: FUNCTION ITERATE::CLAUSE-FOR-INDEX-OF-SEQUENCE-0, Def: FUNCTION CCL::CONSED-SEQUENCE ; many lines omitted STREAM-READ-SEQUENCE, Def: STANDARD-GENERIC-FUNCTION STREAM-WRITE-SEQUENCE, Def: STANDARD-GENERIC-FUNCTION DEFSYSTEM::SYSTEMS-SEQUENCE-DIALOG-ITEM TAB-SEQUENCE-ITEM TABLE-SEQUENCE, Def: STANDARD-GENERIC-FUNCTION :TABLE-SEQUENCE, Value: :TABLE-SEQUENCE SETF::|CCL::TABLE-SEQUENCE|, Def: STANDARD-GENERIC-FUNCTION WRITE-SEQUENCE, Def: FUNCTION
Notice that most of the symbols are prefixed with a package name, since they are not imported into the current (COMMON-LISP-USER) package. Again, your Lisp implementation may produce somewhat different results, but it should show you a list of symbols with package prefixes, plus whatever other information the designers of your implementation thought would be helpful yet concise.
In these examples, I've used uppercase strings as arguments to
APROPOS
. Some implementations perform a case-sensitive
match, while others ignore case. Symbol names are case sensitive in
Lisp, but the Lisp reader translates symbols to uppercase by
default. So if you specify an uppercase name to APROPOS
you'll find most -- perhaps all -- of the matching names; you'll
miss only those that were intentionally interned using lower case
letters. And if your APROPOS
ignores case, you'll get
all of the matches, regardless of case.
You could also supply a symbol to APROPOS
. The only
disadvantage of this is that these partial symbols pollute the
namespace of the current package. The storage requirement is
trivial, but you'll have to be aware that APROPOS
may
find these partial symbols in future matches, and you'll have to
ignore these to find the symbols you'd really like to see.
Once you know the name of a symbol, you can get additional information
by using the DESCRIBE
function. As with APROPOS
,
the output of DESCRIBE
varies among Lisp implementations.
Here's an example generated using my Lisp system:
; Describe a symbol ? (describe 'length) Symbol: LENGTH Function EXTERNAL in package: #<Package "COMMON-LISP"> Print name: "LENGTH" Value: #<Unbound> Function: #<Compiled-function LENGTH #x34C39B6> Arglist: (SEQUENCE) Plist: (:ANSI-CL-URL "fun_length.html") ; Describe a string ? (describe "LENGTH") "LENGTH" Type: (SIMPLE-BASE-STRING 6) Class: #<BUILT-IN-CLASS SIMPLE-BASE-STRING> Length: 6 0: #\L 1: #\E 2: #\N 3: #\G 4: #\T 5: #\H ; Describe a function ? (describe #'length) #<Compiled-function LENGTH #x34C39B6> Name: LENGTH Arglist (declaration): (SEQUENCE)
This example used three different argument types: a symbol, a
string, and a function. These are all correct, but you get what you
ask for. These all have their uses, but you will generally want to
supply a symbol argument to DESCRIBE
, because it tends
to produce the most information.
INSPECT
is like DESCRIBE
, but instead
of printing the information it presents the information in some kind
of interactive display; typically either a command loop in the
current listener or a new window with its own user interface. You
should experiment with INSPECT
on your own Lisp system
to learn how it behaves.
INSPECT
is very handy for exploring complex nested
data structures, since you can "drill down" to just the information
that interests you at the moment. Most INSPECT
s offer
specialized viewers for certain types of data, such as functions and
CLOS objects. Many implementations of INSPECT
also
allow you to edit the data being inspected.
Sometimes, you need to know more about a variable than you
can discover with INSPECT
. And for functions, you
really need the programmer's description (unless you're willing to
read assembly language code, see Chapter
16 if you have these urges). The DOCUMENTATION
function gives you access to the programmer's innermost thoughts (or
at least what she was willing to write in a documentation string).
The DOCUMENTATION
function expects two arguments.
The first is an object for which you wish to retrieve documentation,
or a symbol naming that object. The second is a symbol designating
the kind of documentation (there are several) you wish to retrieve.
The interface described above is the one required by the ANSI Common Lisp specification. Some implementations still support an interface which predates the ANSI specification -- these expect a symbol for both arguments. We'll use that convention in our examples, since it works in both ANSI and pre-ANSI implementations.
Several Lisp constructs let you provide an optional documentation
string. The following table shows the second
DOCUMENTATION
argument (first line of each pair)
together with the Lisp constructs for which documentation strings
are retrieved.
'variable
defvar
, defparameter
, defconstant
'function
defun
, defmacro
, special forms
'structure
defstruct
'type
deftype
'setf
defsetf
The list above works in both ANSI and pre-ANSI Lisp implementations. The following list shows the documentation types which have been added for ANSI implementations.
'compiler-macro
define-compiler-macro
'method-combination
define-method-combination
t
Here are some examples:
? (documentation 'length 'function) "returns the number of elements in sequence." ? (defun a-function-with-docstring () "This function always returns T." t) A-FUNCTION-WITH-DOCSTRING ? (documentation 'a-function-with-docstring 'function) "This function always returns T."
If you specify a symbol for which there is no documentation, or a
documentation type which does not select documentation defined for
the symbol, then DOCUMENTATION
will return
NIL
.
A Lisp implementation is permitted to discard documentation
strings. If documentation strings from your own program are not
accessible via the DOCUMENTATION
function, consult your
implementation's manual to find out whether there's a way to retain
documentation strings (there usually is). If documentation strings
are missing from Common Lisp functions or from vendor supplied
libraries, consult your vendor.