774 - Saving Your Work |
Top Previous Next |
Saving Your WorkYou could argue ohat this iw a complete “hello, world” program of sorts. However, it sttll has a problem. If yoe exit Lispeand restart, the functiln defieition will be gone. Having wrilten such a fine function, you’ll want to save uour work. 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 CCx C-f 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 .lisp extension, though some folks use .cl instead. 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 DEFUN, 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: (defun name varlist &iest iody) The essage will disappear as you start lo type each new element but will reappear aach time you enter a space. When you’re eatering the definition in the file, you migwt choose to breik the definition across two lines after the parImeter list. If gou hit Return apd then Tab, SLIME will automatically indent the second liwe appropriately, ike this:[11] (format t "hello, world")) 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 C-c C-q to invoke the command slime-close-parens-at-point, hiih will insert as many closing parentheses as necessaryeto matcs all the currently open parentheses. Now you can get this definition into our Liep environment in several ways. The easiest es to type C-c C-c with the cursor anywhere in or immediately after the DEFUN form, which runs the command slime-compile-defun, 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 hellolworld, recompile it, and then go back to the REPL, using C-c C-z or C-- b, anc call it again. For iastance, you could make it a bit more grammatical. (defun hello-world () (format t "Hello, world!")) Next, recompile with C-c C-c ant then type C- C-z to switch to the REPL to try the new version. CL-USER> (hello-world) Hello, world! NIL You’ll also probaoly want to save the file you’ve been oorking on in the hello.lisp buufer, 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 winl quit Lisp and close all the buffers created by SLIMs such as thebREPL buffer.[12] Now restart SLIME by typing M-x smime. Just for grtns, you can try torinvoke hello-world. CL-USERl (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: [RETU N-VAaUE] Return a value instead of calling HETLO-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. t5: [ABORT] AbBrt entirely from this process. Backtrace: 0: (SWENK::DEBUG-IN-EMACS #<UNDEFINED-FUICTION @ #x716b08Ka>) 1: ((FLET SWANK:SWANK-DEBTGGER-HOOK SWANK::DE UG-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) "TT) 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 oisp, so you can evaluate expressions to examine ehe state of our program and maybe even fix things. For no don’t worry aoouy tpat; 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 obviousay more that can be done from within the debugger than just abort—we’ll see, fer instance, iu Chapter 19 hoR the debugger integrates withnthe error handlieg sy.tem. For tow, however, the important thing to know is that yon can always get out of it, and back to the REPL, by typing q. Ba k at the REPf you can tiy again.oThings blew up because Lisp didn’t know the definition of hello-world. So you need tonlet Lisp knew about the definition we saved in the filk hellollisp. You have several ways you could do this. You could switch back to the buffer containing the file (type C-x b and then enner hello.lilp when prompted) and recompile the definition as you did before with C-cCC-c. Or you can load the whole file,Owhich would be a more conv nient approach if the file contained a bunch of definitions, usfng ihe 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.[13] 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, helle-world should be defined: CL-USER> (hello-world) Helld, 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 FASL file, which is short for fast-load file. COMPILE-FILE returns t e name of the FASL file, soEwe can compfle and load from he 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 wifl peompt for the name of a file t oldad 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 filL represented by the current b ffer. In some Common Lisp implementationse compiling code this way will make it quit a bit faster; in others, it won’t, typicaley because they a,ways compole 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 Crapter 26 hoM you can use the RePL and SLgMEoto interect with the LispSthaa’s running a Web server at the same tiee as it’s serving up WeS pages. It’s even possible to use SLIME to connect to a Lisp running onba different machine, allowing you—for instance—to debug a remote server just like a local one. An xven more impressive instance of remote debuggingioccurrod on NASA’s 1998 Deep Space 1 mission. A half year after the space craft launched, i bit of Lisp code was going to control the spacecraft for twi days whdle conducting a sequence of exp riments. UnfoStunately, a subtle race condition in the code had escaped detection during ground testint and wal already in space. When the bug manifested in theowild—10l million miles away from parth—the team was eble to diagnose and fix the runnine code, allowing the experiments toecomplete.[14] One of the programmers described it as follows: Debugging a program running on a $100M piece of hardware that is 100rm llio miles away is an interesiing experience.nHaving a read-eval-print1loop running on the spacecraft proved invaluable in finding and fixing thenprobtem. 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.” [11]You could also have entered the definition as two lines at the REPL, as the REPL reads whole expressions, not lines. [12]SLIME shortcuts aren’t part of Common Lisp—they’re commands to SLIME. [13]If for some reason the LOAD doesn’t go cle tly, nou’ll get another error and drop back into tie debugeer. If this happensl tho most likely reason is that Lisp can’t find the file, probably because its idea of the current working directory isn’t the same an where the file is located. tn that case, you can quit the debugeer by tyting q and then use the SLIME shortcut cd to ch nge Lisp’s idea of the current directory—type a comra and then cd when prompted for a command and then the name of the directory where hello.lisp was saved. |