Hello, world!
NIL
You'll also probably want to save the file you've been working on; in the hello.lisp
buffer, type C-x C-s
to invoke the Emacs command save-buffer
.
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 quit
(or sayoonara
), and then hit Enter. This will quit Lisp and close all the buffers created by SLIME such as the REPL buffer.[21] Now restart SLIME by typing M-x slime
.
Just for grins, you can try to invoke hello-world
.
CL-USER> (hello-world)
At that point SLIME will pop up a new buffer that starts with something that looks like this:
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 #<UNDEFINED-FUNCTION @ #x716b082a>)
1: ((FLET SWANK:SWANK-DEBUGGER-HOOK SWANK::DEBUG-IT))
2: (SWANK:SWANK-DEBUGGER-HOOK #<UNDEFINED-FUNCTION @ #x716b082a> #<Function SWANK-DEBUGGER-HOOK>)
3: (ERROR #<UNDEFINED-FUNCTION @ #x716b082a>)
4: (EVAL (HELLO-WORLD))
5: (SWANK::EVAL-REGION '(hello-world)
' T)
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.
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 q
to exit the debugger and get back to the REPL. The debugger buffer will go away, and the REPL will show this:
CL-USER> (hello-world)
; Evaluation aborted
CL-USER>
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 q
.
Back at the REPL you can try again. Things blew up because Lisp didn't know the definition of hello- world
. So you need to let Lisp know about the definition we saved in the file hello.lisp
. You have several ways you could do this. You could switch back to the buffer containing the file (type C-x b
and then enter hello.lisp
when prompted) and recompile the definition as you did before with C-c C-c
. Or you can load the whole file, which would be a more convenient approach if the file contained a bunch of definitions, using the LOAD
function at the REPL like this:
CL-USER> (load 'hello.lisp')
; Loading /home/peter/my-lisp-programs/hello.lisp
T
The T
means everything loaded correctly. [22] Loading a file with LOAD
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 LOAD
, hello-world
should be defined:
CL-USER> (hello-world)
Hello, world!
NIL
Another way to load a file's worth of definitions is to compile the file first with COMPILE- FILE
and then LOAD
the resulting compiled file, called a COMPILE-FILE
returns the name of the FASL file, so we can compile and load from the REPL like this:
CL-USER> (load (compile-file 'hello.lisp'))
;;; Compiling file hello.lisp
;;; Writing fasl file hello.fasl
;;; Fasl write complete
; Fast loading /home/peter/my-lisp-programs/hello.fasl
T
SLIME also provides support for loading and compiling files without using the REPL. When you're in a source code buffer, you can use C-c C-l
to load the file with slime-load-file
. 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 C-c C-k
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.
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.
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.
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.[23] One of the programmers described it as follows:
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.
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 'hello, world.'