One could argue that programming by means of purposefully invoking errors and then immediately fixing them is an unusual way of writing programs. It is, however, particularly effective in Smalltalk, which is another image-based programming language including a full debugger along with a complete development environment - and also possible in Lisp. The idea of this means of programming is to write an invalid code snippet and attempt executing it, causing an immediate entry into the debugger for one of multiple reasons: unbound variables, undefined functions, type errors, argument count mismatches, and so on. The programmer can then use the debugging facilities of the programming language to "fix" the error and continue program execution. This process can be repeated multiple times until the programmer is satisfied with how the code works. A reader familiar with the concept of test-driven development (TDD) may notice a similarity to the "red-green-refactor" paradigm used as a foundation of this development technique: the command passed to the REPL can be thought of as a failing unit test, which is the "red" phase; the process of working in the debugger in order to continue execution can be thought of as fixing the code to pass this unit test, which is the "green" phase; finally, the moment of adjusting the written code to better suit the programming style is the literal definition of the verb "refactor". We can show an example of such programming flow. Let us attempt to define a small Lisp package, `greeter`, which will export simple functionality to greet people. We will start at a fresh Lisp REPL in our hypothetical Lisp implementation. In that REPL, we will immediately attempt to refer to the `greeter` package, and obviously, the Lisp system is going to alert us to the fact that the package does not yet exist: ```lisp CL-USER> (greeter:greet "Thomas") ;; ;; Debugger entered on READER-PACKAGE-ERROR: ;; The name "GREETER" does not designate any package. ;; ;; Available restarts: ;; 0 [CONTINUE ] Use the current package, COMMON-LISP-USER. ;; 1 [RETRY ] Retry finding the package. ;; 2 [USE-VALUE] Specify a different package ;; 3 [UNINTERN ] Read the symbol as uninterned. ;; 4 [SYMBOL ] Specify a symbol to return. ;; 5 [ABORT ] Return to the top level. ;; ;; Enter a restart number to be invoked ;; or an expression to be evaluated. [1] Debug> ``` We can note that there are several available restarts which we can utilize to continue execution. If we inspect the backtrace, we can notice that the error was signaled while reading the Lisp form passed to the REPL; this means that interning the `greeter:greet` symbol failed due to the `greeter` package being unavailable. The `continue` restart will use the current package, `common-lisp-user`, which is not what we want; for similar reasons, we do not want `unintern`. We should be able to use the `retry`, `use-value`, or `symbol` restarts, but only once the `greeter` package exists. Therefore, let's create it. ```lisp [1] Debug> (make-package :greeter :use '(#:cl)) # [1] Debug> (invoke-restart 'retry) ;; ;; Debugger entered on READER-PACKAGE-ERROR: ;; Symbol "GREET" not found in the GREETER package. ;; ;; Available restarts: ;; 0 [CONTINUE] Use symbol anyway. ;; 1 [RETRY ] Retry looking for the symbol. ;; 2 [ABORT ] Return to top level. ;; ;; Enter a restart number to be invoked ;; or an expression to be evaluated. ``` We land in the debugger again. This time, the package has been found, but it does not contain a symbol named `greet`. We can manually intern that symbol into the `greeter` package to fix this error, and then non-forcibly retry looking for the symbol via the `retry` restart. ```lisp [1] Debug> (intern "GREET" (find-package :greeter)) GREETER::GREET NIL [1] Debug> (invoke-restart 'retry) ;; ;; Debugger entered on READER-PACKAGE-ERROR: ;; The symbol "GREET" is not external in the GREETER package. ;; ;; Available restarts: ;; 0 [CONTINUE] Use symbol anyway. ;; 1 [RETRY ] Retry accessing the symbol. ;; 2 [ABORT ] Return to top level. ;; ;; Enter a restart number to be invoked ;; or an expression to be evaluated. [1] Debug> ``` We land in the debugger again - the symbol exists in the package, but it is not exported from it. ```lisp [1] Debug> (export 'greeter::greet (find-package :greeter)) T [1] Debug> (invoke-restart 'retry) ;; ;; Debugger entered on UNDEFINED-FUNCTION: ;; The function GREETER:GREET is undefined. ;; ;; Available restarts: ;; 0 [CONTINUE ] Retry calling GREETER:GREET. ;; 1 [USE-VALUE ] Call specified function. ;; 2 [RETURN-VALUE ] Return specified values. ;; 3 [RETURN-NOTHING] Return zero values. ;; 4 [RETRY ] Retry evaluating the form. ;; 5 [ABORT ] Return to top level. ;; ;; Enter a restart number to be invoked ;; or an expression to be evaluated. [1] Debug> ``` We land in the debugger *yet again*. (Do not worry - we will do it a few more times in a row.) This time, accessing the symbol has succeeded, but there is no function named by that symbol. That is expected, since the symbol has just been created and we have not yet defined any functions associated with it. We will want to use the `continue` restart in order to call the function once it is defined; because of this, the restarts `use-value`, `return-value`, and `return-nothing` are not useful for us in this particular context. Let us switch to the `greeter` package for convenience (so we do not have to prefix all of its internal symbols with `greeter::`) and define that function, implementing its body - all without leaving the debugger. ```lisp [1] Debug> (in-package #:greeter) # [1] Debug> (defun greet (name) (incf (gethash name *greeted-people* 0)) (format ";; Hello, ~A! This is the ~:R time I greet you.~%" name (gethash name *greeted-people*))) GREET [1] Debug> (invoke-restart 'continue) ;; ;; Debugger entered on UNBOUND-VARIABLE: ;; The variable GREETER::*GREETED-PEOPLE* is unbound. ;; ;; Available restarts: ;; 0 [CONTINUE ] Retry using GREETER::*GREETED-PEOPLE*. ;; 1 [USE-VALUE ] Use specified value. ;; 2 [STORE-VALUE] Set specified value and use it. ;; 3 [RETRY ] Retry evaluating the form. ;; 4 [ABORT ] Return to top level. ;; ;; Enter a restart number to be invoked ;; or an expression to be evaluated. [1] Debug> ``` We are progressing. The variable `*greeted-people*` is indeed unbound, but if Common Lisp has signaled this condition, it means that the body of function `greet` - which uses this variable - has been entered, which we can verify by inspecting the backtrace. However, for now, let us fix this immediate error by defining that variable. We will want it its value to be a hash table suitable for utilizing strings as keys: ```lisp [1] Debug> (defvar *greeted-people* (make-hash-table :test #'equal)) *GREETED-PEOPLE* [1] Debug> (invoke-restart 'continue) ;; ;; Debugger entered on PROGRAM-ERROR: ;; Invalid number of arguments to FORMAT: got 1, but expected at least 2. ;; ;; Available restarts: ;; 0 [RETRY ] Retry evaluating the form. ;; 1 [ABORT ] Return to top level. ;; ;; Enter a restart number to be invoked ;; or an expression to be evaluated. [1] Debug> ``` Uh oh. We have made a mistake in the body of `greet` - we forgot to pass the destination argument to it. Let us promptly fix it by redefining `greet` and invoking the `retry` restart to reevaluate the `(greeter:greet "Thomas")` form. ```lisp [1] Debug> (defun greet (name) (incf (gethash name *greeted-people* 0)) (format t ";; Hello, ~A! This is the ~:R time I greet you.~%" name (gethash name *greeted-people*))) GREET [1] Debug> (invoke-restart 'retry) ;; Hello, Thomas! This is the second time I greet you. NIL GREETER> ``` We have successfully left the debugger, though one issue still persists: the formatted output states that this is the *second* time that Tom has been greeted. This is because the first, failed invocation of `greet` has managed to increase the greet count even though the FORMAT call has not succeeded. Let us fix that by cleaning the hash table and quickly testing the function in the REPL. ```lisp GREETER> (clrhash *greeted-people*) # GREETER> (greeter:greet "Thomas") ;; Hello, Thomas! This is the first time I greet you. NIL GREETER> (greeter:greet "Thomas") ;; Hello, Thomas! This is the second time I greet you. NIL GREETER> (greeter:greet "Thomas") ;; Hello, Thomas! This is the third time I greet you. NIL ``` Our code now works properly. This is the time for tracing the steps we have made in the REPL and cleaning up the code we've passed for evaluation. We may e.g. want to merge the three calls to `make-package`, `intern`, and `export` into a single `defpackage` form, and to modify the `greet` function to only increase the greet count once the `format` call has succeeded. Once we've done that, we are ready to start another development cycle by entering the Lisp form that we want to work into the REPL, then hacking away in the debugger until it actually *does* work in the way we intend, and then cleaning up the hard-earned code we've passed to the REPL and saving it to a Lisp source file.