emacs.d/clones/gigamonkeys.com/book/lather-rinse-repeat-a-tour-of-the-repl.html

431 lines
No EOL
32 KiB
HTML
Raw Blame History

<HTML><HEAD><TITLE>Lather, Rinse, Repeat: A Tour of the REPL</TITLE><LINK REL="stylesheet" TYPE="text/css" HREF="style.css"/></HEAD><BODY><DIV CLASS="copyright">Copyright &copy; 2003-2005, Peter Seibel</DIV><H1>2. Lather, Rinse, Repeat: A Tour of the REPL</H1><P>In this chapter you'll set up your programming environment and write
your first Common Lisp programs. We'll use the easy-to-install Lisp
in a Box developed by Matthew Danish and Mikel Evins, which packages
a Common Lisp implementation with Emacs, a powerful Lisp-aware text
editor, and SLIME,<SUP>1</SUP> a
Common Lisp development environment built on top of Emacs.</P><P>This combo provides a state-of-the-art Common Lisp development
environment that supports the incremental, interactive development
style that characterizes Lisp programming. The SLIME environment has
the added advantage of providing a fairly uniform user interface
regardless of the operating system and Common Lisp implementation you
choose. I'll use the Lisp in a Box environment in order to have a
specific development environment to talk about; folks who want to
explore other development environments such as the graphical
integrated development environments (IDEs) provided by some of the
commercial Lisp vendors or environments based on other editors
shouldn't have too much trouble translating the basics.<SUP>2</SUP></P><A NAME="choosing-a-lisp-implementation"><H2>Choosing a Lisp Implementation</H2></A><P>The first thing you have to do is to choose a Lisp implementation.
This may seem like a strange thing to have to do for folks used to
languages such as Perl, Python, Visual Basic (VB), C#, and Java. The
difference between Common Lisp and these languages is that Common
Lisp is defined by its standard--there is neither a single
implementation controlled by a benevolent dictator, as with Perl and
Python, nor a canonical implementation controlled by a single
company, as with VB, C#, and Java. Anyone who wants to read the
standard and implement the language is free to do so. Furthermore,
changes to the standard have to be made in accordance with a process
controlled by the standards body American National Standards
Institute (ANSI). That process is designed to keep any one entity,
such as a single vendor, from being able to arbitrarily change the
standard.<SUP>3</SUP>
Thus, the Common Lisp standard is a contract between any Common Lisp
vendor and Common Lisp programmers. The contract tells you that if
you write a program that uses the features of the language the way
they're described in the standard, you can count on your program
behaving the same in any conforming implementation.</P><P>On the other hand, the standard may not cover everything you may want
to do in your programs--some things were intentionally left
unspecified in order to allow continuing experimentation by
implementers in areas where there wasn't consensus about the best way
for the language to support certain features. So every implementation
offers some features above and beyond what's specified in the
standard. Depending on what kind of programming you're going to be
doing, it may make sense to just pick one implementation that has the
extra features you need and use that. On the other hand, if we're
delivering Lisp source to be used by others, such as libraries,
you'll want--as far as possible--to write portable Common Lisp. For
writing code that should be mostly portable but that needs facilities
not defined by the standard, Common Lisp provides a flexible way to
write code &quot;conditionalized&quot; on the features available in a
particular implementation. You'll see an example of this kind of code
in Chapter 15 when we develop a simple library that smoothes over
some differences between how different Lisp implementations deal with
filenames. </P><P>For the moment, however, the most important characteristic of an
implementation is whether it runs on our favorite operating system.
The folks at Franz, makers of Allegro Common Lisp, are making
available a trial version of their product for use with this book
that runs on Linux, Windows, and OS X. Folks looking for an
open-source implementation have several options. SBCL<SUP>4</SUP> is a high-quality open-source implementation that
compiles to native code and runs on a wide variety of Unixes,
including Linux and OS X. SBCL is derived from CMUCL,<SUP>5</SUP> which is a Common Lisp developed at Carnegie Mellon University,
and, like CMUCL, is largely in the public domain, except a few
sections licensed under Berkeley Software Distribution (BSD) style
licenses. CMUCL itself is another fine choice, though SBCL tends to
be easier to install and now supports 21-bit Unicode.<SUP>6</SUP> For OS X users, OpenMCL
is an excellent choice--it compiles to machine code, supports
threads, and has quite good integration with OS X's Carbon and Cocoa
toolkits. Other open-source and commercial implementations are
available. See Chapter 32 for resources from which you can get more
information. </P><P>All the Lisp code in this book should work in any conforming Common
Lisp implementation unless otherwise noted, and SLIME will smooth out
some of the differences between implementations by providing us with
a common interface for interacting with Lisp. The output shown in
this book is from Allegro running on GNU/Linux; in some cases, other
Lisp's may generate slightly different error messages or debugger
output. </P><A NAME="getting-up-and-running-with-lisp-in-a-box"><H2>Getting Up and Running with Lisp in a Box</H2></A><P>Since the Lisp in a Box packaging is designed to get new Lispers up
and running in a first-rate Lisp development environment with minimum
hassle, all you need to do to get it running is to grab the
appropriate package for your operating system and the preferred Lisp
from the Lisp in a Box Web site listed in Chapter 32 and then follow
the installation instructions.</P><P>Since Lisp in a Box uses Emacs as its editor, you'll need to know at
least a bit about how to use it. Perhaps the best way to get started
with Emacs is to work through its built-in tutorial. To start the
tutorial, select the first item of the Help menu, Emacs tutorial. Or
press the Ctrl key, type <CODE>h</CODE>, release the Ctrl key, and then
press <CODE>t</CODE>. Most Emacs commands are accessible via such key
combinations; because key combinations are so common, Emacs users
have a notation for describing key combinations that avoids having to
constantly write out combinations such as &quot;Press the Ctrl key, type
<CODE>h</CODE>, release the Ctrl key, and then press <CODE>t</CODE>.&quot; Keys to be
pressed together--a so-called key chord--are written together and
separated by a hyphen. Keys, or key chords, to be pressed in sequence
are separated by spaces. In a key chord, <CODE>C</CODE> represents the Ctrl
key and <CODE>M</CODE> represents the Meta key (also known as Alt). Thus,
we could write the key combination we just described that starts the
tutorial like so: <CODE>C-h t</CODE>.</P><P>The tutorial describes other useful commands and the key combinations
that invoke them. Emacs also comes with extensive online
documentation using its own built-in hypertext documentation browser,
Info. To read the manual, type <CODE>C-h i</CODE>. The Info system comes
with its own tutorial, accessible simply by pressing <CODE>h</CODE> while
reading the manual. Finally, Emacs provides quite a few ways to get
help, all bound to key combos starting with <CODE>C-h</CODE>. Typing
<CODE>C-h ?</CODE> brings up a complete list. Two of the most useful,
besides the tutorial, are <CODE>C-h k</CODE>, which lets us type any key
combo and tells us what command it invokes, and <CODE>C-h w</CODE>, which
lets us enter the name of a command and tells us what key combination
invokes it. </P><P>The other crucial bit of Emacs terminology, for folks who refuse to
work through the tutorial, is the notion of a <I>buffer</I>. While
working in Emacs, each file you edit will be represented by a
different buffer, only one of which is &quot;current&quot; at any given time.
The current buffer receives all input--whatever you type and any
commands you invoke. Buffers are also used to represent interactions
with programs such as Common Lisp. Thus, one common action you'll
take is to &quot;switch buffers,&quot; which means to make a different buffer
the current buffer so you can edit a particular file or interact with
a particular program. The command <CODE>switch-to-buffer</CODE>, bound to
the key combination <CODE>C-x b</CODE>, prompts for the name of a buffer in
the area at the bottom of the Emacs frame. When entering a buffer
name, hitting Tab will complete the name based on the characters
typed so far or will show a list of possible completions. The prompt
also suggests a default buffer, which you can accept just by hitting
Return. You can also switch buffers by selecting a buffer from the
Buffers menu.</P><P>In certain contexts, other key combinations may be available for
switching to certain buffers. For instance, when editing Lisp source
files, the key combo <CODE>C-c C-z</CODE> switches to the buffer where you
interact with Lisp. </P><A NAME="free-your-mind-interactive-programming"><H2>Free Your Mind: Interactive Programming</H2></A><P>When you start Lisp in a Box, you should see a buffer containing a
prompt that looks like this:</P><PRE>CL-USER&gt;</PRE><P>This is the Lisp prompt. Like a Unix or DOS shell prompt, the Lisp
prompt is a place where you can type expressions that will cause
things to happen. However, instead of reading and interpreting a line
of shell commands, Lisp reads Lisp expressions, evaluates them
according to the rules of Lisp, and prints the result. Then it does
it again with the next expression you type. That endless cycle of
reading, evaluating, and printing is why it's called the
<I>read-eval-print loop</I>, or REPL for short. It's also referred to as
the <I>top-level</I>, the <I>top-level listener</I>, or the <I>Lisp
listener</I>.</P><P>From within the environment provided by the REPL, you can define and
redefine program elements such as variables, functions, classes, and
methods; evaluate any Lisp expression; load files containing Lisp
source code or compiled code; compile whole files or individual
functions; enter the debugger; step through code; and inspect the
state of individual Lisp objects.</P><P>All those facilities are built into the language, accessible via
functions defined in the language standard. If you had to, you could
build a pretty reasonable programming environment out of just the
REPL and any text editor that knows how to properly indent Lisp code.
But for the true Lisp programming experience, you need an
environment, such as SLIME, that lets you interact with Lisp both via
the REPL and while editing source files. For instance, you don't want
to have to cut and paste a function definition from a source file to
the REPL or have to load a whole file just because you changed one
function; your Lisp environment should let us evaluate or compile
both individual expressions and whole files directly from your
editor. </P><A NAME="experimenting-in-the-repl"><H2>Experimenting in the REPL</H2></A><P>To try the REPL, you need a Lisp expression that can be read,
evaluated, and printed. One of the simplest kinds of Lisp expressions
is a number. At the Lisp prompt, you can type <CODE>10</CODE> followed by
Return and should see something like this:</P><PRE>CL-USER&gt; 10
10</PRE><P>The first <CODE>10</CODE> is the one you typed. The Lisp reader, the <I>R</I>
in REPL, reads the text &quot;10&quot; and creates a Lisp object representing
the number 10. This object is a <I>self-evaluating</I> object, which
means that when given to the evaluator, the <I>E</I> in REPL, it
evaluates to itself. This value is then given to the printer, which
prints the <CODE>10</CODE> on the line by itself. While that may seem like
a lot of work just to get back to where you started, things get a bit
more interesting when you give Lisp something meatier to chew on. For
instance, you can type <CODE>(+ 2 3)</CODE> at the Lisp prompt.</P><PRE>CL-USER&gt; (+ 2 3)
5</PRE><P>Anything in parentheses is a list, in this case a list of three
elements, the symbol <CODE>+</CODE>, and the numbers 2 and 3. Lisp, in
general, evaluates lists by treating the first element as the name of
a function and the rest of the elements as expressions to be
evaluated to yield the arguments to the function. In this case, the
symbol <CODE>+</CODE> names a function that performs addition. 2 and 3
evaluate to themselves and are then passed to the addition function,
which returns 5. The value 5 is passed to the printer, which prints
it. Lisp can evaluate a list expression in other ways, but we needn't
get into them right away. First we have to write. . . </P><A NAME="hello-world-lisp-style"><H2>&quot;Hello, World,&quot; Lisp Style</H2></A><P>No programming book is complete without a &quot;hello, world&quot;<SUP>7</SUP> program.
As it turns out, it's trivially easy to get the REPL to print &quot;hello,
world.&quot;</P><PRE>CL-USER&gt; &quot;hello, world&quot;
&quot;hello, world&quot;</PRE><P>This works because strings, like numbers, have a literal syntax
that's understood by the Lisp reader and are self-evaluating objects:
Lisp reads the double-quoted string and instantiates a string object
in memory that, when evaluated, evaluates to itself and is then
printed in the same literal syntax. The quotation marks aren't part
of the string object in memory--they're just the syntax that tells
the reader to read a string. The printer puts them back on when it
prints the string because it tries to print objects in the same
syntax the reader understands.</P><P>However, this may not really qualify as a &quot;hello, world&quot; <I>program</I>.
It's more like the &quot;hello, world&quot; <I>value</I>. </P><P>You can take a step toward a real program by writing some code that
as a side effect prints the string &quot;hello, world&quot; to standard output.
Common Lisp provides a couple ways to emit output, but the most
flexible is the <CODE><B>FORMAT</B></CODE> function. <CODE><B>FORMAT</B></CODE> takes a variable
number of arguments, but the only two required arguments are the
place to send the output and a string. You'll see in the next chapter
how the string can contain embedded directives that allow you to
interpolate subsequent arguments into the string, <20> la <CODE>printf</CODE>
or Python's string-<CODE>%</CODE>. As long as the string doesn't contain an
<CODE>~</CODE>, it will be emitted as-is. If you pass <CODE>t</CODE> as its first
argument, it sends its output to standard output. So a <CODE><B>FORMAT</B></CODE>
expression that will print &quot;hello, world&quot; looks like this:<SUP>8</SUP></P><PRE>CL-USER&gt; (format t &quot;hello, world&quot;)
hello, world
NIL</PRE><P>One thing to note about the result of the <CODE><B>FORMAT</B></CODE> expression is
the <CODE><B>NIL</B></CODE> on the line after the &quot;hello, world&quot; output. That
<CODE><B>NIL</B></CODE> is the result of evaluating the <CODE><B>FORMAT</B></CODE> expression,
printed by the REPL. (<CODE><B>NIL</B></CODE> is Lisp's version of false and/or
null. More on that in Chapter 4.) Unlike the other expressions we've
seen so far, a <CODE><B>FORMAT</B></CODE> expression is more interesting for its
side effect--printing to standard output in this case--than for its
return value. But every expression in Lisp evaluates to some
result.<SUP>9</SUP></P><P>However, it's still arguable whether you've yet written a true
&quot;program.&quot; But you're getting there. And you're seeing the bottom-up
style of programming supported by the REPL: you can experiment with
different approaches and build a solution from parts you've already
tested. Now that you have a simple expression that does what you
want, you just need to package it in a function. Functions are one of
the basic program building blocks in Lisp and can be defined with a
<CODE><B>DEFUN</B></CODE> expression such as this: </P><PRE>CL-USER&gt; (defun hello-world () (format t &quot;hello, world&quot;))
HELLO-WORLD</PRE><P>The <CODE>hello-world</CODE> after the <CODE><B>DEFUN</B></CODE> is the name of the
function. In Chapter 4 we'll look at exactly what characters can be
used in a name, but for now suffice it to say that lots of
characters, such as <CODE>-</CODE>, that are illegal in names in other
languages are legal in Common Lisp. It's standard Lisp style--not to
mention more in line with normal English typography--to form compound
names with hyphens, such as <CODE>hello-world</CODE>, rather than with
underscores, as in <CODE>hello_world</CODE>, or with inner caps such as
<CODE>helloWorld</CODE>. The <CODE>()</CODE>s after the name delimit the
parameter list, which is empty in this case because the function
takes no arguments. The rest is the body of the function.</P><P>At one level, this expression, like all the others you've seen, is
just another expression to be read, evaluated, and printed by the
REPL. The return value in this case is the name of the function you
just defined.<SUP>10</SUP> But like the <CODE><B>FORMAT</B></CODE> expression, this
expression is more interesting for the side effects it has than for
its return value. Unlike the <CODE><B>FORMAT</B></CODE> expression, however, the side
effects are invisible: when this expression is evaluated, a new
function that takes no arguments and with the body <CODE>(format t
&quot;hello, world&quot;)</CODE> is created and given the name <CODE>HELLO-WORLD</CODE>.</P><P>Once you've defined the function, you can call it like this:</P><PRE>CL-USER&gt; (hello-world)
hello, world
NIL</PRE><P>You can see that the output is just the same as when you evaluated
the <CODE><B>FORMAT</B></CODE> expression directly, including the <CODE><B>NIL</B></CODE> value
printed by the REPL. Functions in Common Lisp automatically return
the value of the last expression evaluated. </P><A NAME="saving-your-work"><H2>Saving Your Work</H2></A><P>You could argue that this is a complete &quot;hello, world&quot; program of
sorts. However, it still has a problem. If you exit Lisp and restart,
the function definition will be gone. Having written such a fine
function, you'll want to save your work.</P><P>Easy enough. You just need to create a file in which to save the
definition. In Emacs you can create a new file by typing <CODE>C-x
C-f</CODE> and then, when Emacs prompts you, entering the name of the file
you want to create. It doesn't matter particularly where you put the
file. It's customary to name Common Lisp source files with a
<CODE>.lisp</CODE> extension, though some folks use <CODE>.cl</CODE> instead.</P><P>Once you've created the file, you can type the definition you
previously entered at the REPL. Some things to note are that after
you type the opening parenthesis and the word <CODE><B>DEFUN</B></CODE>, at the
bottom of the Emacs window, SLIME will tell you the arguments
expected. The exact form will depend somewhat on what Common Lisp
implementation you're using, but it'll probably look something like
this:</P><PRE>(defun name varlist &amp;rest body)</PRE><P>The message will disappear as you start to type each new element but
will reappear each time you enter a space. When you're entering the
definition in the file, you might choose to break the definition
across two lines after the parameter list. If you hit Return and then
Tab, SLIME will automatically indent the second line appropriately,
like this:<SUP>11</SUP></P><PRE>(defun hello-world ()
(format t &quot;hello, world&quot;))</PRE><P>SLIME will also help match up the parentheses--as you type a closing
parenthesis, it will flash the corresponding opening parenthesis. Or
you can just type <CODE>C-c C-q</CODE> to invoke the command
<CODE>slime-close-parens-at-point</CODE>, which will insert as many closing
parentheses as necessary to match all the currently open parentheses.</P><P>Now you can get this definition into your Lisp environment in several
ways. The easiest is to type <CODE>C-c C-c</CODE> with the cursor anywhere
in or immediately after the <CODE><B>DEFUN</B></CODE> form, which runs the command
<CODE>slime-compile-defun</CODE>, which in turn sends the definition to
Lisp to be evaluated and compiled. To make sure this is working, you
can make some change to <CODE>hello-world</CODE>, recompile it, and then go
back to the REPL, using <CODE>C-c C-z</CODE> or <CODE>C-x b</CODE>, and call it
again. For instance, you could make it a bit more grammatical. </P><PRE>(defun hello-world ()
(format t &quot;Hello, world!&quot;))</PRE><P>Next, recompile with <CODE>C-c C-c</CODE> and then type <CODE>C-c C-z</CODE> to
switch to the REPL to try the new version.</P><PRE>CL-USER&gt; (hello-world)
Hello, world!
NIL</PRE><P>You'll also probably want to save the file you've been working on; in
the <CODE>hello.lisp</CODE> buffer, type <CODE>C-x C-s</CODE> to invoke the Emacs
command <CODE>save-buffer</CODE>.</P><P>Now to try reloading this function from the source file, you'll need
to quit Lisp and restart. To quit you can use a SLIME shortcut: at
the REPL, type a comma. At the bottom of the Emacs window, you will
be prompted for a command. Type <CODE>quit</CODE> (or <CODE>sayoonara</CODE>),
and then hit Enter. This will quit Lisp and close all the buffers
created by SLIME such as the REPL buffer.<SUP>12</SUP> Now restart SLIME
by typing <CODE>M-x slime</CODE>. </P><P>Just for grins, you can try to invoke <CODE>hello-world</CODE>. </P><PRE>CL-USER&gt; (hello-world)</PRE><P>At that point SLIME will pop up a new buffer that starts with
something that looks like this:</P><PRE>attempt to call `HELLO-WORLD' which is an undefined function.
[Condition of type UNDEFINED-FUNCTION]
Restarts:
0: [TRY-AGAIN] Try calling HELLO-WORLD again.
1: [RETURN-VALUE] Return a value instead of calling HELLO-WORLD.
2: [USE-VALUE] Try calling a function other than HELLO-WORLD.
3: [STORE-VALUE] Setf the symbol-function of HELLO-WORLD and call it again.
4: [ABORT] Abort handling SLIME request.
5: [ABORT] Abort entirely from this process.
Backtrace:
0: (SWANK::DEBUG-IN-EMACS #&lt;UNDEFINED-FUNCTION @ #x716b082a&gt;)
1: ((FLET SWANK:SWANK-DEBUGGER-HOOK SWANK::DEBUG-IT))
2: (SWANK:SWANK-DEBUGGER-HOOK #&lt;UNDEFINED-FUNCTION @ #x716b082a&gt; #&lt;Function SWANK-DEBUGGER-HOOK&gt;)
3: (ERROR #&lt;UNDEFINED-FUNCTION @ #x716b082a&gt;)
4: (EVAL (HELLO-WORLD))
5: (SWANK::EVAL-REGION &quot;(hello-world)
&quot; T)</PRE><P>Blammo! What happened? Well, you tried to invoke a function that
doesn't exist. But despite the burst of output, Lisp is actually
handling this situation gracefully. Unlike Java or Python, Common
Lisp doesn't just bail--throwing an exception and unwinding the
stack. And it definitely doesn't dump core just because you tried to
invoke a missing function. Instead Lisp drops you into the debugger. </P><P>While you're in the debugger you still have full access to Lisp, so
you can evaluate expressions to examine the state of our program and
maybe even fix things. For now don't worry about that; just type
<CODE>q</CODE> to exit the debugger and get back to the REPL. The debugger
buffer will go away, and the REPL will show this:</P><PRE>CL-USER&gt; (hello-world)
; Evaluation aborted
CL-USER&gt;</PRE><P>There's obviously more that can be done from within the debugger than
just abort--we'll see, for instance, in Chapter 19 how the debugger
integrates with the error handling system. For now, however, the
important thing to know is that you can always get out of it, and
back to the REPL, by typing <CODE>q</CODE>. </P><P>Back at the REPL you can try again. Things blew up because Lisp
didn't know the definition of <CODE>hello-world</CODE>. So you need to let
Lisp know about the definition we saved in the file
<CODE>hello.lisp</CODE>. You have several ways you could do this. You could
switch back to the buffer containing the file (type <CODE>C-x b</CODE> and
then enter <CODE>hello.lisp</CODE> when prompted) and recompile the
definition as you did before with <CODE>C-c C-c</CODE>. Or you can load the
whole file, which would be a more convenient approach if the file
contained a bunch of definitions, using the <CODE>LOAD</CODE> function at
the REPL like this:</P><PRE>CL-USER&gt; (load &quot;hello.lisp&quot;)
; Loading /home/peter/my-lisp-programs/hello.lisp
T</PRE><P>The <CODE><B>T</B></CODE> means everything loaded correctly.<SUP>13</SUP>
Loading a file with <CODE>LOAD</CODE> is essentially equivalent to typing
each of the expressions in the file at the REPL in the order they
appear in the file, so after the call to <CODE><B>LOAD</B></CODE>, <CODE>hello-world</CODE>
should be defined:</P><PRE>CL-USER&gt; (hello-world)
Hello, world!
NIL</PRE><P>Another way to load a file's worth of definitions is to compile the
file first with <CODE><B>COMPILE-FILE</B></CODE> and then <CODE><B>LOAD</B></CODE> the resulting
compiled file, called a <I>FASL file</I>, which is short for
<I>fast-load file</I>. <CODE><B>COMPILE-FILE</B></CODE> returns the name of the FASL
file, so we can compile and load from the REPL like this: </P><PRE>CL-USER&gt; (load (compile-file &quot;hello.lisp&quot;))
;;; Compiling file hello.lisp
;;; Writing fasl file hello.fasl
;;; Fasl write complete
; Fast loading /home/peter/my-lisp-programs/hello.fasl
T</PRE><P>SLIME also provides support for loading and compiling files without
using the REPL. When you're in a source code buffer, you can use
<CODE>C-c C-l</CODE> to load the file with <CODE>slime-load-file</CODE>. Emacs
will prompt for the name of a file to load with the name of the
current file already filled in; you can just hit Enter. Or you can
type <CODE>C-c C-k</CODE> to compile and load the file represented by the
current buffer. In some Common Lisp implementations, compiling code
this way will make it quite a bit faster; in others, it won't,
typically because they always compile everything.</P><P>This should be enough to give you a flavor of how Lisp programming
works. Of course I haven't covered all the tricks and techniques yet,
but you've seen the essential elements--interacting with the REPL
trying things out, loading and testing new code, tweaking and
debugging. Serious Lisp hackers often keep a Lisp image running for
days on end, adding, redefining, and testing bits of their program
incrementally.</P><P>Also, even when the Lisp app is deployed, there's often still a way
to get to a REPL. You'll see in Chapter 26 how you can use the REPL
and SLIME to interact with the Lisp that's running a Web server at
the same time as it's serving up Web pages. It's even possible to use
SLIME to connect to a Lisp running on a different machine, allowing
you--for instance--to debug a remote server just like a local one. </P><P>An even more impressive instance of remote debugging occurred on
NASA's 1998 Deep Space 1 mission. A half year after the space craft
launched, a bit of Lisp code was going to control the spacecraft for
two days while conducting a sequence of experiments. Unfortunately, a
subtle race condition in the code had escaped detection during ground
testing and was already in space. When the bug manifested in the
wild--100 million miles away from Earth--the team was able to
diagnose and fix the running code, allowing the experiments to
complete.<SUP>14</SUP> One
of the programmers described it as follows:</P><BLOCKQUOTE>Debugging a program running on a $100M piece of hardware that is
100 million miles away is an interesting experience. Having a
read-eval-print loop running on the spacecraft proved invaluable in
finding and fixing the problem.</BLOCKQUOTE><P>You're not quite ready to send any Lisp code into deep space, but in
the next chapter you'll take a crack at writing a program a bit more
interesting than &quot;hello, world.&quot;
</P><HR/><DIV CLASS="notes"><P><SUP>1</SUP>Superior Lisp Interaction Mode for Emacs</P><P><SUP>2</SUP>If
you've had a bad experience with Emacs previously, you should treat
Lisp in a Box as an IDE that happens to use an Emacs-like editor as
its text editor; there will be no need to become an Emacs guru to
program Lisp. It is, however, orders of magnitude more enjoyable to
program Lisp with an editor that has some basic Lisp awareness. At a
minimum, you'll want an editor that can automatically match
<CODE>()</CODE>s for you and knows how to automatically indent Lisp code.
Because Emacs is itself largely written in a Lisp dialect, Elisp, it
has quite a bit of support for editing Lisp code. Emacs is also
deeply embedded into the history of Lisp and the culture of Lisp
hackers: the original Emacs and its immediate predecessors, TECMACS
and TMACS, were written by Lispers at the Massachusetts Institute of
Technology (MIT). The editors on the Lisp Machines were versions of
Emacs written entirely in Lisp. The first two Lisp Machine Emacs,
following the hacker tradition of recursive acronyms, were EINE and
ZWEI, which stood for EINE Is Not Emacs and ZWEI Was EINE Initially.
Later ones used a descendant of ZWEI, named, more prosaically,
ZMACS.</P><P><SUP>3</SUP>Practically speaking, there's very little likelihood
of the language standard itself being revised--while there are a
small handful of warts that folks might like to clean up, the ANSI
process isn't amenable to opening an existing standard for minor
tweaks, and none of the warts that might be cleaned up actually cause
anyone any serious difficulty. The future of Common Lisp
standardization is likely to proceed via de facto standards, much
like the &quot;standardization&quot; of Perl and Python--as different
implementers experiment with application programming interfaces
(APIs) and libraries for doing things not specified in the language
standard, other implementers may adopt them or people will develop
portability libraries to smooth over the differences between
implementations for features not specified in the language standard.</P><P><SUP>4</SUP>Steel Bank
Common Lisp</P><P><SUP>5</SUP>CMU Common
Lisp</P><P><SUP>6</SUP>SBCL
forked from CMUCL in order to focus on cleaning up the internals and
making it easier to maintain. But the fork has been amiable; bug
fixes tend to propagate between the two projects, and there's talk
that someday they will merge back together.</P><P><SUP>7</SUP>The
venerable &quot;hello, world&quot; predates even the classic Kernighan and
Ritchie C book that played a big role in its popularization. The
original &quot;hello, world&quot; seems to have come from Brian Kernighan's &quot;A
Tutorial Introduction to the Language B&quot; that was part of the <I>Bell
Laboratories Computing Science Technical Report #8: The Programming
Language B</I> published in January 1973. (It's available online at
<CODE>http://cm.bell-labs.com/cm/cs/who/dmr/bintro.html</CODE>.)</P><P><SUP>8</SUP>These
are some other expressions that also print the string &quot;hello,
world&quot;:</P><P><SUP>9</SUP>Well, as you'll see when I discuss returning multiple
values, it's technically possible to write expressions that evaluate
to no value, but even such expressions are treated as returning
<CODE>NIL</CODE> when evaluated in a context that expects a value.</P><P><SUP>10</SUP>I'll discuss in Chapter 4 why the name has been
converted to all uppercase.</P><P><SUP>11</SUP>You could also have entered the definition as two
lines at the REPL, as the REPL reads whole expressions, not lines.</P><P><SUP>12</SUP>SLIME shortcuts aren't
part of Common Lisp--they're commands to SLIME.</P><P><SUP>13</SUP>If for some reason
the <CODE><B>LOAD</B></CODE> doesn't go cleanly, you'll get another error and drop
back into the debugger. If this happens, the most likely reason is
that Lisp can't find the file, probably because its idea of the
current working directory isn't the same as where the file is located.
In that case, you can quit the debugger by typing <CODE>q</CODE> and then
use the SLIME shortcut <CODE>cd</CODE> to change Lisp's idea of the current
directory--type a comma and then <CODE>cd</CODE> when prompted for a command
and then the name of the directory where <CODE>hello.lisp</CODE> was saved.</P><P><SUP>14</SUP><CODE>http://www.flownet.com/gat/jpl-lisp.html</CODE></P></DIV></BODY></HTML>