This is the final post of my series on storing data as Lisp programs (see here, here, here, here, and here). I hope that those of you have read the whole series have a new or renewed appreciation for the concept of data as code that is one half of the data/code duality that Lisp provides. Today, I want discuss, just a bit, how I leveraged the power of Emacs to develop and debug the sample code in the series.
I’ve written before about how you can think of Emacs As A Lisp Machine: that is, the power of Lisp is always available to you. As an example of this, consider the “program” file that I used to develop code for the series. Here’s a screen shot of almost the entire buffer. Cut off at the top are 3 more records and an enclosing (log ...)
sexpr that is assigned to log-file
.
The thing to notice is that there are no real programs there, just a bunch of record and function definitions, a list of the tag names for the record structure and a few other miscellaneous pieces of code.
Walking through the process for the third problem of the previous post will make the process clear. I began by copying the list of tag names to the bottom of the file, narrowing to the list, and then running a keyboard macro on the narrowed buffer that changed each name into a call to defalias
that defined the name as an alias for identity
. Then I cut exception
, frame
, and record
out of the list and changed the 'identity
to 'list
. All that’s just basic editing but with Emacs it involved almost no work: probably about 50 keystrokes total.
The next thing I did was to highlight the new function definitions and run eval-region
. After that the new functions were defined and I could go to the end of one of the records and type 【Ctrl+x Ctrl+e】 to execute the record. That’s where the block showing the arguments to record
came from.
Finally, I wrote the final 6 functions in the file and ran eval-region
on them. That completed the solution to the third problem. I tested the solution first on each of the 4 records by running 【Ctrl+x Ctrl+e】 on each of them and then an actual filtering run by typing 【Ctrl+x Ctrl+e】 at the end of
(setq result (remove-if-not 'eval (cdr log-file)))
That resulted in the two records that passed the criteria being put in result
.
The whole process is much more trouble to write down then it was to actually do. Emacs’ superb editing powers allowed me to write the support functions with an absolute minimum of effort and then to test and refine them interactively. Notice that there wasn’t even a REPL involved except for the implicit REPL that Emacs is always running as you type things into a buffer. The ability to select some code and execute it is tremendously powerful and liberating. And fast. During this development, I never left the filter-log.el
buffer. There was no need to go to a separate REPL buffer, or to run a compile, or anything else.
I don’t program like this all the time, of course. Sometimes you just write a program or part of a program and then test it but when you’re feeling your way along—when you’re doing exploratory programming—it’s very nice to be able to write and try a snippet of code as small as a single statement. After a while, you begin to understand the problem better and you can drop back to the normal process of writing larger segments of code. At least until you need to do a little exploring again. Emacs supports both styles seamlessly and it’s easy to switch back and forth as needed. The power of Emacs can be astounding, even to those of us who are used to it.