09fe133e6c33

This took a while
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Sat, 04 Aug 2018 12:57:08 -0700
parents 9dea95450c02
children 15d99aa7fd90
branches/tags (none)
files content/blog/2018/07/a-road-to-common-lisp.markdown content/blog/2018/08/a-road-to-common-lisp.markdown

Changes

--- a/content/blog/2018/07/a-road-to-common-lisp.markdown	Sat Aug 04 12:55:21 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1207 +0,0 @@
-+++
-title = "A Road to Common Lisp"
-snip = "One way to learn this old, deep language."
-date = 2018-07-03T16:00:00Z
-draft = false
-
-+++
-
-I've gotten a bunch of emails asking for advice on how to learn Common Lisp in
-the present day.  I decided to write down all the advice I've been giving
-through email and social media posts in the hopes that someone might find it
-useful.
-
-<div id="toc"></div>
-
-## Context
-
-I think it's important to have a general sense of where Common Lisp came from
-and what kind of a language it is before you start learning it.  There are a lot
-of things that will seem very strange if you're coming straight from modern
-languages, but will make a lot more sense if you've got a bit of background
-context.
-
-### History
-
-Lisp and Common Lisp have a long, deep history.  I'm not going to try to cover
-it all here — if you're interested you should check out some of the following
-(in roughly increasing order of detail):
-
-* Wikipedia's [History of Lisp][wiki-history-lisp] and [History of Common Lisp][wiki-history-cl].
-* The [Where it Began section in Practical Common Lisp][pcl-history].
-* The [History: Where did Lisp come from?][cll-history] section of the comp.lang.lisp FAQ.
-* [Common Lisp: the Untold Story][untold] by Kent Pitman.
-* [The Evolution of Lisp][evolution] by Guy Steele and Richard Gabriel.
-
-I realize you probably won't want to read all of the links above immediately, so
-here's a whirlwind tour of sixty years of Lisp.
-
-Lisp began in the late 1950's.  It was invented by John McCarthy at MIT.
-
-Over the next twenty or so years various versions and dialects of Lisp grew and
-flourished.  Some of the more notable dialects were Maclisp, BBN Lisp/Interlisp,
-Franz Lisp, Spice Lisp, and Lisp Machine Lisp.  There were others too.  The
-point is that there were a *lot* of different implementations, all growing,
-changing, and trying out different things.
-
-(Scheme also originated in this time frame, but took a very different route and
-diverged from the path we're looking at.  I won't cover Scheme in this post.)
-
-In the early 1980s people decided that having a whole slew of
-mutually-incompatible dialects of Lisp might be not be the most desirable
-situation to be in.  An effort was made to take these different languages that
-had grown organically and produce one common language that would satisfy the
-needs of everyone.  In 1984 the first edition of Guy Steele's [Common Lisp: the
-Language][cltl] was published.
-
-If you do some math you'll see that at the time the book was published Lisp had
-around twenty-five years of real-world use, experimentation, experience, and
-history to draw upon.  Even so, the book alone didn't quite satisfy everyone and
-in 1986 a committee (X3J13) was formed to produce an ANSI specification for
-Common Lisp.
-
-As the committee worked on the standardization process, in 1990 the second
-edition of Common Lisp: the Language was published.  This was more comprehensive
-and contained some of the things the committee was working on (see the
-comp.lang.lisp FAQ linked above for more on this).  At this point the Lisp
-family of languages had over 30 years of experience and history to draw upon.
-For comparison: Python (a "modern" language many people think of as also being
-"kind of old") [was released][python] for the first time the following year.
-
-In 1992 the X3J13 committee published the first draft of the new ANSI standard
-for Common Lisp for public review (see Pitman's paper).  The draft was approved
-in 1994 and the approved specification was finally published in 1995.  At this
-point Lisp was over thirty-five years old.  The first version of Ruby [was
-released][rubby] in December of that year.
-
-That's the end of the history lesson.  There has not been another revision of
-the ANSI specification of Common Lisp.  The version published in 1995 is the one
-that is still used today — if you see something calling itself "an
-implementation of Common Lisp" today, that is the specification it's referring
-to.
-
-### Consequences
-
-So why am I telling you all this?  Because I want you to know what you're
-getting yourself into.  I want you to realize that Common Lisp is a stable,
-large, practical, extensible, ugly language.  Understanding these
-characteristics will make a lot of things make more sense as you learn the
-language.
-
-#### Escaping the Hamster Wheel of Backwards Incompatibility
-
-If you're coming from other languages, you're probably used to things breaking.
-If you want to run Ruby code written ten years ago on the latest version of
-Ruby, it's probably going to take some time to update it.  My current day job is
-in Scala, and if a library's last activity is more than 2 or 3 years old on
-Github I just assume it won't work without a significant amount of screwing
-around on my part.  The Hamster Wheel of Backwards Incompatibility we deal with
-every day is a fact of life in most modern languages (though some are certainly
-better than others).
-
-If you learn Common Lisp, this is not the case.  In the next section of this
-post I'll be recommending a book written in 1990.  You can run its code,
-unchanged, in a Common Lisp implementation released last month.  After years of
-jogging on the Hamster Wheel of Backwards Incompatibility I cannot tell you how
-much of a relief it is to be able to write code and reasonably expect it to
-still work in twenty years.
-
-Of course, this is only the case for the language itself — if you depend on any
-libraries there's always the chance they might break when you update them.  But
-I've found the stability of the core language is contagious, and overall the
-Common Lisp community seems fairly good about maintaining backwards
-compatibility.
-
-I'll be honest though: there are exceptions.  As you learn the language and
-start using libraries you'll start noticing some library authors who don't
-bother to document and/or preserve stable APIs for their libraries, and if
-staying off the Hamster Wheel is important to you you'll learn to avoid relying
-on code written by those people as much as possible.
-
-This may sound a little bleak, but it's made a bit better by some other
-characteristics of Common Lisp: it's a large, practical language.  The second
-edition of Common Lisp: the Language (usually abbreviated as "CLtL2" by Common
-Lisp programmers) is 971 pages long, not including the preface, references, or
-index.  When programming in Common Lisp people will tend to depend on
-a small(ish) number of libraries, and library writers often try to minimize
-dependencies by utilizing as much of the core language as possible.
-I personally try to stick to fewer than ten or so dependencies for my
-applications and no more than two or three for my libraries, but I'm probably
-a bit more conservative here than most folks (I *really* don't like the Hamster
-Wheel any more).
-
-It's also worth noting that since Common Lisp has been around and stable for so
-long, it has *libraries* older and more stable than many programming languages.
-For example: Bordeaux Threads (the de-facto threading library for Common Lisp)
-was first proposed in 2004 and released soon after (2006 at the latest but
-possibly earlier, it's hard to tell because so many links are dead now), which
-makes it fourteen years old.  So yes, threading is handled by a library, but I'm
-not worried about it breaking my code in the next decade or two.
-
-As you learn Common Lisp and look for libraries, try to suppress the voice in
-the back of your head that says "This project was last updated six years ago?
-That's probably abandoned and broken."  The stability of Common Lisp means that
-sometimes libraries can just be *done*, not *abandoned*, so don't dismiss them
-out of hand.
-
-#### Extensibility and Power
-
-Part of Common Lisp's practicality comes from its extensibility.  No one has
-been clamoring for a new version of the specification that adds features because
-Common Lisp gives users enough power to add new features to the language as
-libraries without having to alter the core language.
-
-Macros are what might come to mind when you hear "Lisp extensibility", and of
-course that's part of it.  Macros allow users to write libraries that would need
-to be core language features in other languages.
-
-Common Lisp doesn't include string interpolation.  You want it?  No problem, you
-don't have to wait for [Scala
-2.10](https://docs.scala-lang.org/overviews/core/string-interpolation.html) or
-[Python 3.6](https://www.python.org/dev/peps/pep-0498/), just [use
-a library][cl-interpol].
-
-Want to try some nondeterministic programming without any boilerplate?  [Grab
-a library][screamer].
-
-Pattern matching syntax can make for some really beautiful, readable code.
-Common Lisp doesn't include it, but of course [there's a library][trivia].
-
-Enjoying algebraic data types in Haskell or Scala?  Here's your [library][cl-adt].
-
-All of these libraries rely on macros to make using them feel seamless.  Of
-course you could *do* all of that without macros, but you've have to add a layer
-of boilerplate to manage evaluation.  This:
-
-    (match foo
-      '(list x y z) (lambda (x y z) (+ x y z))
-      '(vector x y) (lambda (x y) (- x y)))
-
-just doesn't flow off the fingers like:
-
-    (match foo
-      ((list x y z) (+ x y z))
-      ((vector x y) (- x y)))
-
-No one's up in arms trying to get a new revision of the Common Lisp standard to
-add pattern matching because you can write it as a library and get 95% or more
-of what you've get if it were built in.  The language gives you enough power to
-extend it in a way that feels like the extension was there from the beginning.
-
-Macros are one of the things that make Lisp so incredibly extensible, because
-they let you transform arbitrary code into other arbitrary code.  This is true
-for macros in languages like C too, but Common Lisp macros are fundamentally
-different because they're *part of the language*.
-
-In C you have a layer of macros on top, written in a separate preprocessor macro
-language.  The macro layer and the language layer are separate from each other,
-with the macro layer providing one one extra level of abstractive power.
-
-In Common Lisp, you write macros *in Common Lisp itself*.  You can then use
-those macros to write functions, and use those functions to write more macros.
-Instead of two stratified layers it's a *feedback loop* of abstractive power.
-
-But macros aren't the only thing about Common Lisp that make it so practical and
-extensible.  Something that people often don't realize is that while Common Lisp
-is an extremely high-level language thanks to macros, it also has plenty of
-low-level facilities as part of the language.  It's never going to be as
-low-level as something like C or Rust, but you might be surprised at some of the
-things that the ANSI spec includes.
-
-Want to see the assembly that a particular function compiles down to?
-[`DISASSEMBLE`][dis] it!
-
-Want to stack-allocate something to avoid some garbage collection?  X3J13
-[thought of that][dynext].
-
-Need arrays of unboxed floats to ship to a graphics card?  [The standard allows
-for that][arrays].
-
-Think `GOTO` should be considered helpful, not harmful?  Well okay, we're all
-adults here.  [Good luck][tagbody], try not to shoot your foot off.
-
-Need to do unsigned 8-bit arithmetic in your Game Boy emulator, but would prefer
-it to compile down to just a machine instruction or two?  [It's
-possible][arith].
-
-Not all Common Lisp implementations actually perform all these optimizations,
-but the designers of Common Lisp had the foresight to include the language
-features needed to support them.  You can write vanilla Common Lisp as defined
-by the standard and trust that it will run everywhere, and implementations that
-*do* support these kinds of things will take advantage of the optimization
-opportunities.
-
-This combination of supporting extremely high-level programming with macros and
-a reasonable amount of low-level optimization mean that even though the
-specification is over twenty years old, it's still a good solid base to build on
-today.  The thirty years of experience and history the designers were drawing
-from allowed them to create a very practical language that has survived for
-decades.
-
-#### Ugliness
-
-It's also important to realize that while Common Lisp might be incredibly
-practical, the need to accommodate existing users and dialects means that there
-are ugly parts.  If you buy a paper copy of the second edition of Common Lisp:
-the Language and look up "kludges" in the index you'll find this:
-
-[![Photo of a page of CLtL2's Index, listing "kludges" as pages 1 to 971](/media/images/blog/2018/07/lisp-kludge.jpeg)](/media/images/blog/2018/07/lisp-kludge.jpeg)
-
-Common Lisp is not a beautiful crystal of programming language design.  It's
-a scruffy workshop with a big pegboard wall of tools, a thin layer of sawdust on
-the floor, a filing cabinet in the office with a couple of drawers that open
-perpendicular to the rest, and there's a weird looking saw with `RPLACD` written
-on the side sitting off in a corner where no one's touched it for twenty years.
-
-This historical baggage is a price paid to ensure Common Lisp had a future.  It
-made it practical for people using the old dialects to actually adopt Common
-Lisp with a reasonable amount of effort.  If the designers had tried to make it
-perfect and beautiful this could have made it too different to port
-implementations and code to and might have resulted in the language being
-ignored, instead of being adopted and embraced.
-
-[wiki-history-cl]: https://en.wikipedia.org/wiki/Common_Lisp#History
-[wiki-history-lisp]: https://en.wikipedia.org/wiki/Lisp_(programming_language)#History
-[cll-history]: https://www.cs.cmu.edu/Groups//AI/lang/lisp/faq/lisp_2.faq
-[pcl-history]: http://www.gigamonkeys.com/book/introduction-why-lisp.html#where-it-began
-[untold]: http://www.nhplace.com/kent/Papers/cl-untold-story.html
-[evolution]: https://www.dreamsongs.com/Files/HOPL2-Uncut.pdf
-[cltl]: https://www.cs.cmu.edu/Groups/AI/html/cltl/cltl2.html
-[python]: https://en.wikipedia.org/wiki/History_of_Python#Early_history
-[rubby]: https://en.wikipedia.org/wiki/Ruby_(programming_language)#First_publication
-[bt-release]: https://web.archive.org/web/20040831185622/http://ww.telent.net/diary/2004/7/#9.57181
-[cl-interpol]: https://edicl.github.io/cl-interpol/
-[screamer]: https://nikodemus.github.io/screamer/
-[trivia]: https://github.com/guicho271828/trivia/wiki/What-is-pattern-matching%3F-Benefits%3F
-[cl-adt]: https://github.com/tarballs-are-good/cl-algebraic-data-type
-[dis]: http://clhs.lisp.se/Body/f_disass.htm
-[dynext]: http://clhs.lisp.se/Body/d_dynami.htm
-[arrays]: http://clhs.lisp.se/Body/15_ab.htm
-[arith]: https://pdfs.semanticscholar.org/7089/0eff0e93aba49174a9346731f4bf9225706d.pdf
-[tagbody]: http://clhs.lisp.se/Body/s_tagbod.htm
-
-## A Road to Learning Common Lisp
-
-If all of this hasn't scared you away from the language, let's talk about how
-you can learn it in 2018.
-
-If you search around on the internet for Common Lisp tutorials and guides,
-you're not going to find as much as you might expect.  This is because a lot of
-Common Lisp reference material was created before and/or during the infancy of
-the internet.  There are a *lot* of books about Common Lisp out there.  Some are
-better than others.  I'll recommend the ones I personally think are the best,
-but don't hesitate to browse around and find others.
-
-One final disclaimer: this is *a* road to Common Lisp, not *the* road to Common
-Lisp.  It's what I followed (without some of the dead ends) and has a lot of my
-personal opinions baked in, but is by no means the only way to learn the
-language.  Ask around and get some more opinions — more options won't hurt!
-
-### Get a Lisp
-
-To get started with Common Lisp you'll need to install a Common Lisp
-implementation.  Remember: Common Lisp is an ANSI specification, so there are
-multiple implementations of it, which gives you choices.  There are a bunch of
-options, but I'll make it simple for you:
-
-* If you're comfortable with the command line, installing packages with a package manager, and already have a text editor you like, choose [SBCL][].
-* Otherwise, choose [ClozureCL][CCL] (often called "CCL").
-
-That's Clozure with a Z.  Clojure is something entirely different that just
-happens to have a confusingly similar name.
-
-You might also hear of something called CLISP, which sounds like it might be
-what you want.  It's not.  CLISP is just another implementation, but it hasn't
-had a release in eight years (even though development is still ongoing in its
-source repos) and it's not as commonly used as CCL or SBCL, so it'll be harder
-to find help if you have questions about the installation, etc.
-
-You might also hear about something called Roswell.  Don't use Roswell, you don't
-need it (yet (or at all)).
-
-Just install SBCL or CCL for now, you can explore the other options once you've
-got your bearings a bit better.
-
-### Pick an Editor
-
-You might hear people tell you that you *must* learn Emacs before learning
-Common Lisp.  They're wrong.  You can get started learning the language just
-fine in whatever text editor you're comfortable in.
-
-If you don't have a preference, CCL itself comes bundled with a text editor on
-MacOS.  That one will work just fine to start.
-
-Emacs, Vim, Sublime Text, Atom, whatever, for now it doesn't matter.  As long as
-it can balance parenthesis and highlight comments and strings, that's all you
-need to start.  Worry about shaving the editor yak once you're more comfortable
-in the language.
-
-### Hello, Lisp
-
-To check that you've got everything set up properly, make a `hello.lisp` file
-with the following contents:
-
-```lisp
-(defun hello ()
-  (write-line "What is your name?")
-  (let ((name (read-line)))
-    (format t "Hello, ~A.~%" name)))
-```
-
-Don't worry about what this means yet, it's just a check that everything's
-working properly.
-
-Open an SBCL or CCL REPL and load the file by entering `(load "hello.lisp")`,
-then call the function and make sure it works.  It should look something like
-this if you picked SBCL:
-
-    $ sbcl
-    * (load "hello.lisp")
-
-    T
-    * (hello)
-    What is your name?
-    Steve
-    Hello, Steve.
-    NIL
-    *
-
-Or this if you chose CCL (the program might be annoyingly named `ccl64` if
-you're on a 64-bit system):
-
-    $ ccl64
-    Clozure Common Lisp Version ...
-
-    ? (load "hello.lisp")
-    #P"/home/sjl/Desktop/hello.lisp"
-    ? (hello)
-    What is your name?
-    Steve
-    Hello, Steve.
-    NIL
-    ?
-
-If your arrow keys and backspace don't work in the REPL, use [`rlwrap`][rlwrap]
-to fix that.  `rlwrap sbcl` will give you a non-miserable REPL.  `rlwrap` is
-a handy tool to have in your toolbox anyway.
-
-[rlwrap]: https://github.com/hanslub42/rlwrap
-
-### A Gentle Introduction
-
-The best book I've found for getting started in Common Lisp is [Common Lisp:
-A Gentle Introduction to Symbolic Computation][book-gentle].  This book really
-does strive to be gentle.  Even if you've programmed before I'd recommend
-starting here because it eases you into the language.  If you find it's moving
-too slow just skim forward a bit.
-
-The 1990 edition is available free from the site, and there's a 2013 reprint
-which fixes some minor errors in the 1990 version.  If you can afford it I'd
-recommend buying the 2013 edition, but the 1990 version will also do fine.
-
-Go through the book and *do all the exercises*.  This will take a while.
-
-This is mainly meant to get you started overcoming some of the main obstacles to
-being comfortable in Common Lisp, like:
-
-* How am I ever going to remember all these weird function names?
-* Why do people use strings so rarely?
-* When do I need/not need the goddamned quotation mark?
-
-You should also join the `#clnoobs` channel on Freenode so you can ask questions
-if you get stuck.  For the most part people there are friendly and helpful,
-though I'll warn you in advance that there's at least one person who can
-sometimes be abrasive.
-
-If IRC isn't your thing there's also a [Discord
-server](https://discord.gg/tffeu2x) that some of us hang out in.  Join the
-`#common-lisp` channel there and we'll be happy to help you.
-
-[book-gentle]: https://www.cs.cmu.edu/~dst/LispBook/
-[SBCL]: http://www.sbcl.org/on
-[CCL]: https://ccl.clozure.com/
-
-### Getting Practical
-
-Once you've finished that book the next one you should attack is [Practical
-Common Lisp][book-pcl].  You can get a paper copy if you want, but the full book
-is available on the site.
-
-You can skip the editor/programming environment part because the environment it
-recommends (Lisp in a Box) is abandoned and no longer works.  Just keep using
-the programming environment you're comfortable with for now.
-
-Unfortunately the book doesn't include exercises.  If you *really* want to get
-the most out of it you can type in all the code as you're reading it and poke at
-it, but if you've already done the exercises in the previous book it's probably
-safe to just sit down and read the book carefully.
-
-Make sure you understand everything as you go through the book.  Don't be afraid
-to ask questions on IRC or Discord (or email me if you want, I don't mind) if
-something's not clear.
-
-You should also begin to get comfortable looking up things in [the Common Lisp
-language specification][clhs] itself.  It's the ultimate manual for Common Lisp.
-It can be pretty dense at points, but can answer many questions you might have.
-You can either use the index page to find what you're looking for or just search
-on Google for "clhs whatever".  CLHS stands for "Common Lisp HyperSpec", which
-is the hyperlinked, HTML version of the spec.
-
-(Some people will tell you to learn the language by just reading the spec.  That's
-ridiculous — it's like trying to learn French by reading a dictionary.  It's
-a useful tool to have, but not the only one you'll need.)
-
-[book-pcl]: http://www.gigamonkeys.com/book/
-[clhs]: http://www.lispworks.com/documentation/lw70/CLHS/Front/Contents.htm
-
-### Make Something
-
-Once you've got those two books under your belt and some practice using the
-spec, it's time to make something without someone holding your hand.  It doesn't
-have to be anything big or special, the goal is to just write some Lisp without
-having the answer on the next page.
-
-If you need some ideas:
-
-* Do some [Project Euler](https://projecteuler.net/) problems.
-* Do some [Advent of Code](https://adventofcode.com/) exercises.
-* Make a [stupid Twitter bot](https://twitter.com/git_commands).
-* Make a personal calendar program that records your appointments, checks the
-  weather forecast the day of, etc.
-
-It doesn't really matter what you make, just make *something* on your own.
-
-### Lisp as a System
-
-At this point it's time to take your Common Lisp skills up a notch.  Up until
-now I've told you to just use any text editor because it's more important to get
-you some experience with the language, but now it's time to move on.
-
-In most languages the development process looks something like this:
-
-1. Edit some code in the project with an editor.
-2. Compile the project (some languages skip this step).
-3. Run the project (or the tests).
-4. Observe the output (in the console, a browser, etc).
-5. Go to 1.
-
-This is not how most Common Lisp users interact with the language.  In Common
-Lisp, the development cycle looks more like this:
-
-1. Start a Lisp process.
-2. Load the project.
-3. Edit some code with your editor.
-4. Tell the running process to compile *only the code you edited*.
-5. Interact with the changed code in the process via the REPL, an HTTP request, etc.
-6. Observe the output (either in the console, a browser, etc).
-7. Go to 3.
-
-When you embrace the Lisp way of working you'll rarely recompile and reload an
-entire project.  Usually you'll write a function (or a macro, or parameter, or
-whatever), compile just that function, maybe poke at it in the REPL a bit, and
-then move on to the next function.  This has some advantages over the
-traditional compile-everything-then-run approach.
-
-First: compiling a small chunk of code is fast.  I just timed compiling a few of
-the larger functions in one of my projects and they took around 50-80
-microseconds.  You don't have to wait for the compiler, so your
-concentration/thought process never has time to wander.
-
-Another advantage is that when you get back the results of your compilation,
-any errors or warnings you receive are almost certainly related to the few
-lines of code you just compiled.  If you compile a ten-line function, run it,
-and get a division by zero error you can immediately focus in on the ten lines
-you just compiled and think about what changed.
-
-Because the Lisp process is always running, as soon as you compile a function
-it's ready to be used in the REPL.  You can throw some arbitrary data at it and
-inspect the results to see how it behaves in isolation before you build more
-things on top of it.
-
-This cycle of making a function, compiling it, poking at it to make sure it's
-working as expected, and moving on happens *constantly*.
-
-In contrast, when working in languages like Scala or Python I almost never find
-myself writing one single function and compiling or running the project
-immediately.  Spinning up the compiler or running the unit tests takes at
-*least* a second or two (or, sometimes *minutes* in Scala, unfortunately) so to
-avoid having a constant stream of gaps in my thought I end up writing a bunch of
-functions at once, and then I run the project or tests once I know they have
-a chance of working.
-
-But then when I get back an error I have much more surface area to check,
-because I've added a lot of new code!  So now I have to track down a problem
-that might be in something I wrote four minutes ago, whereas in Lisp I would
-only have to ever look at the code I wrote in the last few seconds.
-
-I've started using IntelliJ with Scala to help make this a bit less painful.  It
-does help with the compile times because it recompiles things on the fly, but it
-doesn't solve the rest of the problem.  I can write a Scala function in IntelliJ
-and it will be compiled immediately, but I can't *interact* with it immediately
-like I can in Common Lisp.
-
-When you work in this style with Common Lisp I think you'll really grow to love
-it.  Writing in other languages will begin to feel like shipping your code off
-to the DMV and getting it back a week with a page full of red ink somewhere in
-the hundred forms you filled out.  Writing in Common Lisp feels like interacting
-with a living, breathing organism, or like [teaching things to an eager
-assistant][eager].
-
-This goes beyond just the short feedback loop and interactive REPL, too.  As an
-example, imagine you're making a video game and have a bug somewhere in your
-damage calculation that will occasionally cause a division by zero.  Now let's
-say you're working on the code for a particular quest.  You'll start the game,
-load a save file at the beginning of the quest, and start going through the
-steps.  All of a sudden, in the middle of killing the final monster for the
-quest, you hit the damage bug!  In traditional languages, one of two things
-might happen:
-
-1. The game crashes, and you get a stack trace and maybe a core dump.
-2. You've wrapped a `try` block around the main game loop that logs a stack
-   trace and ignores errors and allows the game to continue.
-
-Case 1 is pretty bad.  You've got to try to track down the bug from a snapshot
-of what things looked like at the time (the stack trace and core dump).  And
-even if you manage to fix it, now you've got to redo all that playing to get
-back to testing your quest code that you were originally working on.
-
-Case 2 is bad, in a different way.  If you just ignore errors all the time, the
-game might now be in a weird state.  You also might lose some critical context
-that's necessary to debug the problem, unless you're also saving a core dump
-(but I don't know of many people who do that).
-
-In Common Lisp you can certainly choose to panic or ignore on errors, but
-there's a better way to work.  When an error is signaled in Common Lisp, it
-doesn't unwind the stack.  The Lisp process will pause execution at that point
-and open a window in your editor showing you the stack trace.  Your warrior's
-sword is hovering at the monster, waiting for you.  At this point you can
-communicate with the running process at the REPL to see what's going on.  You
-can examine variables in the stack, or even run any arbitrary code you want.
-
-Once you figure out the problem ("Oh, I see, the `calculate-armor-percentage`
-function returns `0` if a shielding spell ran out during the same frame") you
-can fix the code, recompile the problematic function, and *restart the execution
-of that function in the call stack*.  Your warrior's sword lands, and you move
-back to what you were doing before.
-
-You don't have to track down the bug from just a stack trace, like a detective
-trying to piece together what happened by the blood stains on the wall.  You can
-examine the crime *as it's happening* and intervene to save the victim.  It's
-like if you could run your code in a debugger with a breakpoint at every single
-line that only activates if something goes wrong!
-
-Maybe you don't make video games.  But this process can be useful in all kinds
-of contexts.  Maybe you're writing a web app that talks to an API somewhere, and
-are debugging a request that fails somewhere between two calls to the API, e.g.
-between "create widget `foo`" and "add `foo` to widget list `bar`".  Instead of
-just aborting the request, logging a stack trace, and now leaving things in
-a possibly weird state (`foo` having been created without being in the expected
-`bar` list), you can fix the problem and allow the request to finish properly.
-
-Of course this won't always work.  If you've got a big function that does some
-side effects and then crashes, restarting execution of the function would make
-the side effects happen again.  But if you divide up your functions well ([one
-function to a function!][1ftaf]) this case is pretty rare.  And even when it
-does happen, it just means you're back in the same situation you're in *by
-default* with other languages!
-
-[eager]: https://www.reddit.com/r/lisp/comments/4oo1cp/common_lisp_for_clojure_programmer/d4eec68/
-[1ftaf]: https://groups.google.com/forum/message/raw?msg=comp.lang.lisp/9SKZ5YJUmBg/Fj05OZQomzIJ
-
-### Learning Paradigms
-
-### Recipes for Success
-
-## Where to Go From Here
-
-If you made it through all the books and activities in the previous section:
-congratulations, you're off to a great start!  Now that you've got a decent
-handle on the core language you can explore in many different directions,
-depending on your interests.
-
-### Macros
-
-If you want to learn the secrets of macros, you'll probably want to read and
-work through [On Lisp][] and [Let Over Lambda][] (in that order).
-
-I'll say that you should take both books (*especially* the latter) with a large
-grain of salt.  A lot of Common Lisp users don't agree with all of the arguments
-and style in these books, but I think they can still provide plenty of value if
-you read them with a critical mind.
-
-[On Lisp]: http://www.paulgraham.com/onlisp.html
-[Let Over Lambda]: https://letoverlambda.com/
-
-### Object-Oriented Programming with CLOS
-
-Common Lisp has some very sophisticated support for Object-Oriented Programming
-through CLOS.  If you have bad memories of OOP from working in a Java cube farm
-like I did, I'd urge you to give CLOS a fair chance to change your mind.
-
-Start with [Object-Oriented Programming in COMMON LISP: A Programmer's Guide to
-CLOS][Keene] — it's a wonderfully-written, short and to-the-point book that will
-give you a good overview of how CLOS is intended to be used.
-
-If you really want to bend your mind, try [The Art of the Metaobject
-Protocol][amop] (usually abbreviated as AMOP).  This book will probably take you
-a couple of tries to get through.  Read it until you hit a mental wall, go work
-on other things for a couple of months, and come back and try again.  Repeat
-that process as many times as necessary.
-
-[Keene]: https://www.amazon.com/Object-Oriented-Programming-COMMON-LISP-Programmers/dp/0201175894
-[amop]: https://www.amazon.com/Art-Metaobject-Protocol-Gregor-Kiczales/dp/0262610744
-
-### Low-Level Programming
-
-Low-level programming can mean a lot of different things.
-
-If you're interested in writing emulators for old computers, I wrote [a series
-of posts][chip8posts] on making a [CHIP-8][] emulator in Common Lisp.
-[cl-6502][] is an emulator for the processor used in the NES (and lots of other
-things) and has a really nice [literate programming][cl-6502-book] version
-that's wonderful to read through.
-
-If you want to interface with C libraries, [CFFI][] is what you want to use.
-The manual is worth reading, though I wish it were a little gentler to start
-with.
-
-[chip8posts]: http://stevelosh.com/blog/2016/12/chip8-cpu/
-[CHIP-8]: https://en.wikipedia.org/wiki/CHIP-8
-[cl-6502]: https://github.com/kingcons/cl-6502
-[cl-6502-book]: http://redlinernotes.com/docs/cl-6502.pdf
-[CFFI]: https://common-lisp.net/project/cffi/
-
-### Web Development
-
-Unfortunately I don't have too many suggestions for web development in Common
-Lisp.  I've made a conscious effort to avoid web development in the past five or
-so years, because it seems like the Hamster Wheel of Backwards Incompatibility
-has become more of a Hamster Centrifuge in that field.
-
-There is a `#lispweb` channel on Freenode and a `#webdev` channel in the Lisp
-Discord, so if you have questions you could start by asking there.  Those
-channels are a bit less populated than the other Lisp channels, so don't expect
-an answer immediately.
-
-### Game Development
-
-Common Lisp has a small but enthusiastic community of people who like making
-games.  There's a `#lispgames` channel on Freenode and a `#gamedev` channel on
-the Lisp Discord that you should join if you're interested.
-
-[Land of Lisp](http://landoflisp.com/) is a fun little book to go through.  The
-coding style in the book has some... "eccentricities", which is why I don't
-recommend it as a first book on Lisp (e.g. using `ash` instead of `truncate` or
-`floor` for integer division), but if you know the language and just want to get
-started making some simple games I think you'll enjoy working through it.
-
-If you want an excuse to make a game in Lisp in a week, the Lisp Game Jam is
-something you can join.  It's usually held once or twice each year, so you'll
-have to search around (or ask in `#lispgames`) to find out when the next one is.
-
-Lisp doesn't have any engine as full-featured as Unity, but several people are
-currently working on making 3D game engines.  Ask around to see what people are
-using these days.  Unfortunately a 3D game engine will generally need to
-interface with the OS to render images and produce audio, and so can't be
-written in pure Common Lisp.  This means that some running on the Hamster Wheel
-of Backwards Incompatibility will be necessary to keep up with OS changes (e.g.
-[Apple deprecating OpenGL][eat-shit-apple]).
-
-If you're interested in old-school ASCII/tile-based games, I've personally done
-some work with using [ncurses][] and [bearlibterminal][] in Common Lisp.
-There's something really fun about making a game people can play over telnet!
-Feel free to get in touch with me if you're interested in that kind of stuff and
-want to know more.
-
-[eat-shit-apple]: https://www.macrumors.com/2018/06/05/apple-deprecates-opengl-opencl-gaming/
-[ncurses]: https://github.com/HiTECNOLOGYs/cl-charms
-[bearlibterminal]: http://foo.wyrd.name/en:bearlibterminal
-
-### Window Management
-
-If you're running Linux and like tinkering with your desktop environment,
-[StumpWM][] is an X window manager written in Common Lisp.  I've just recently
-switched back to Linux so I've only been using it for a month or so, but it's
-really pleasant to be able to customize my working environment with Common Lisp.
-
-StumpWM has a small but friendly community — if you're looking for a non-trivial
-open source Common Lisp project to contribute to, StumpWM would be a great
-choice.
-
-[StumpWM]: https://stumpwm.github.io/
-
-### Unit Testing
-
-If you're coming from a modern language, especially one with a lot of
-"test-driven development" advocates, you might be surprised at the lack of an
-emphasis on unit testing in Common Lisp.  I think one reason for this is that in
-some languages a unit test is the simplest way to actually *run* a function,
-but Lisp's interactive style of development gives you an even easier
-alternative: just run the function in the REPL!
-
-Despite the lack of heavy unit testing in the community, there are almost as
-many unit testing *frameworks* as there are Common Lisp programmers!  This is
-probably because making a unit testing framework is so easy with a few macros.
-I personally love [1am][], but there are *plenty* more to choose from.
-
-Whichever one you choose, please make sure to be a good citizen and create
-a separate ASDF system for your unit tests, so people can use your library
-without having to load Yet Another Testing Framework.
-
-[1am]: https://github.com/lmj/1am
-
-## Modern Common Lisp
-
-Common Lisp is old and stable, but that doesn't mean it's stagnant.  The
-language gives you plenty of power to build on, and before I wrap this up I want
-go over a couple of things that often trip up new people.
-
-### Structure
-
-Common Lisp's terminology for various parts of projects is often confusing to
-new people because it's old and uses a lot of words that we use now (like
-“package”) to mean different things than people mean today. Things get easier
-once you internalize what Common Lisp means by the terms.
-
-NOTE: I posted a quick-and-dirty version of this section as a [comment][] on Lobste.rs
-while I was waiting for a plane — this section of the post is an expanded
-version of that comment.
-
-[comment]: https://lobste.rs/s/fwhuz5/my_lisp_journey_1_getting_started_with#c_ebhvzq
-
-#### Packages
-
-We often see questions in `#clnoobs` that look something like: "How do I export
-a class from a package"?  Questions worded like this are a sign of a very common
-misunderstanding about what packages in Common Lisp *actually are*.
-
-A package in Common Lisp is **a container for symbols**.  That's it.  They're
-a way to group related names (symbols) together so you don't have to do the
-miserable prefixing of every name with `mylibrary-...` like you need to do in
-Emacs Lisp or C to avoid name clashes.
-
-You don't export a class from a package, you export a *symbol*.  You don't
-import a function, you import the *symbol* it's attached to.  This sounds
-pedantic, but is important to keep clear in your head as you start using the
-package system.  If you're not clear on what exactly a symbol *is*, I wrote
-a [separate post][symbols] just about symbols which you might find helpful.
-
-Another major tripping point for new people is the relationship between packages
-and files.  Or, rather, the completely *lack* of any relationship in Common
-Lisp.
-
-In many languages like Python, Java, or Clojure, a file's package and its
-location on the hard drive are tied together.  For example: when you say `import
-foo.bar.baz` in Python, Python will look for a `baz.py` inside the `foo/bar/`
-folder (it's a little more complicated than this, but that doesn't matter for
-this example).
-
-In Common Lisp, this is not the case.  **Files and packages are completely
-orthogonal in Common Lisp.**  You can have many files that all work in the same
-package, or one file that switches between many packages, or even create or
-modify packages at runtime.
-
-This gives you maximum flexibility to work however you want.  For example: in my
-[Prolog VM][temperance] most of the packages are each defined in their own file,
-much like you would do in modern languages.  But the `temperance.compiler` TODO
-package is pretty large (the compiler is the most complicated part of the code)
-and so I split it into [a series of separate files][temperance-compiler], each
-one dealing with a single pass of the compiler, which all work in the same
-package.
-
-So if files and packages aren't related, the next question is: how does Common
-Lisp know where to *find* anything on disk when it comes time to load the code?
-
-[symbols]: TODO
-[temperance]: TODO
-[temperance-compiler]: TODO
-
-#### Systems
-
-A system in Common Lisp is a collection of serveral things:
-
-* The code.
-* A description of how to load that code.
-* A list of other systems this system depends on, which need to be loaded prior
-  to loading this one.
-* Some metadata like author, license, version, homepage, etc.
-
-The Common Lisp language itself has no knowledge of systems.  If you look at
-chapter TODO of CLtL2 you'll see that it was imagined that each library author
-would write their own custom file to load their code.
-
-Of course, since Common Lisp gives you the power to abstract almost anything,
-people eventually abstracted the process of loading Common Lisp code.
-
-ASDF is a Common Lisp library bundled with most (all?) modern implementations
-which handles defining and loading systems.  The name ASDF stands for "Another
-System Definition Facility", so as you might guess there have been several other
-such libraries.  ASDF is the one everyone uses today.
-
-ASDF standardizes the process of defining a system into something like this:
-
-* The system definition(s) for a project called `foo` would be in a file named `foo.asd`.
-* Each system is defined with a `(defsystem ...)` form inside this file.
-
-We'll talk more about what a "project" is shortly.  Note the extension of the
-file is `asd`, not `asdf`, which is a little confusing, but was probably chosen
-to work in environments with three-letter-extension limits.
-
-The [ASDF manual][TODO] is the definitive resource for the syntax and semantics
-of `defproject`, but can be a little heavy to read if you're just getting
-started.  Another way to get started is to read some `.asd` files of some
-small-to-medium sized open source projects and see how they handle things.
-
-Systems and packages are orthogonal in Common Lisp.  Some systems (like small
-libraries) will define exactly one package.  Some systems will define multiple
-packages.  Rarely a system might not define any new packages, but will use or
-add to an existing one.
-
-For example:
-
-* My directed graph library [cl-digraph][] contains a system called `cl-digraph`.
-* That system has a description of how to load the code, which lives in the [`cl-digraph.asd`][cl-digraph-asd] file.
-* As part of loading the system it will load the file [`packages.lisp`][cl-digraph-packages], which creates a package called `digraph`.
-
-Even though ASDF standardizes some aspects of system definition, it still gives
-you plenty of flexibility.  As you read projects by different authors you'll
-encounter different ways of organizing systems — this can be a little
-overwhelming at first, but it means you can organize a system in the way that
-works *best for that system*, which is really nice once you've got some
-experience under your belt.
-
-One example of this is how people define packages for their systems.  There are
-a couple of common ways to do this you'll see in the wild:
-
-* A single `package.lisp` file which contains all the definitions for all the
-  packages in the project, and gets loaded before all other files.  This is the
-  strategy I usually prefer.
-* Each file defines its package at the top of the file, much like you would in
-  Clojure or other modern languages.  Care is taken in the system definition to
-  load the files in the correct order so that each package is defined before it
-  is ever used.
-
-So to recap: a system is a collection of code and a description of how to load
-it, a list of its dependencies, and some metadata.  Now let's move up one level
-higher to the final layer of structure you need to know about.
-
-[cl-digraph]: TODO
-[cl-digraph-asd]: TODO
-[cl-digraph-packages]: TODO
-
-#### Projects
-
-A project in Common Lisp is not an official term defined anywhere that I know
-of, but is a word that's generally used to mean something like a library,
-a framework, an application, etc.
-
-A project will usually define at least one system, because systems are where you
-describe how to load the code, and if a project didn't define a system how would
-you know how to load its code?  My cl-digraph library mentioned above is
-a project that defines *three* systems:
-
-The `cl-digraph` system contains the actual data structure and API.  It has no
-dependencies.
-
-The `cl-digraph.test` system contains the unit tests.  It depends on the
-`cl-digraph` system (because that's the code it's going to test) and the `1am`
-system (a unit test framework).  I made this a separate system because it allows
-users to load the main code without also having to load the unit testing
-framework if they're not going to be running the tests.
-
-The `cl-digraph.dot` system contains code for drawing the directed graphs to
-image files with [Graphviz][TODO].  It depends on the `cl-digraph` system and
-the `cl-dot` system (the Graphviz bindings).  I made this a separate system
-because it allows users load the main code without also having to load the
-Graphviz bindings if they don't care about drawing.
-
-If I were writing this project today I'd use a forward slash in the system names
-instead of a period (e.g. `cl-digraph/test`), because ASDF has some nice [extra
-support][TODO] for that.  I just didn't know about it at the time, and don't
-want to break backwards compatibility now.
-
-We saw how Common Lisp has no concept of a system — that concept comes from
-ASDF.  Similarly, ASDF has no concept of the internet or of reaching out to
-somewhere to download things.  ASDF assumes you have somehow acquired the
-systems you want to load and stored them on your hard drive, perhaps by sending
-a check to an address and receiving a copy of the code on floppy disk, as many
-of my old Lisp books offer in their final pages.
-
-Quicklisp is another library that works on top of ASDF to provide the "download
-projects from the internet automatically if necessary" functionality that people
-expect in the modern world.  So when you say `(ql:quickload :cl-digraph)` you’re
-asking Quicklisp to download cl-digraph (and any dependencies) if necessary, and
-then hand it off to ASDF to actually load the code of the `cl-digraph` system.
-Unlike ASDF, Quicklisp is relatively new in the Common Lisp world (it's only
-about eight years old) and so is not bundled with any modern Lisp
-implementations that I know of (yet?), which is why you need to install it
-separately.
-
-#### Recap
-
-Here's a quick recap of the different layers of project structure you'll
-encounter in Common Lisp:
-
-* **Files** are files on your hard drive.
-* **Packages** are containers of symbols. They are orthogonal to files.
-* **Systems** are collections of code, instructions on how to load this code,
-  dependency lists, and metadata. They are orthogonal to packages.
-* **Projects** are high-level collections of... "stuff" such as code,
-  documentation, maybe some image assets, etc. They are (mostly) orthogonal to
-  systems (are you seeing a trend here?).
-* Common Lisp itself knows about files and packages.
-* ASDF adds systems.
-* Quicklisp adds the internet.
-
-#### Naming Conventions
-
-One more small thing we should talk about before moving on is how to name
-things.  This section is only my personal opinion, so some other folks will
-probably disagree.  You should consider their arguments and your own needs and
-decide for yourself.
-
-You can name your packages anything you want, but your users will thank you if
-you follow a couple of simple rules.  First, don't do the overly-verbose style
-of naming packages like `com.stevelosh.cl-digraph.digraph`.  Unfortunately
-Common Lisp doesn't have a portable way to add package-local nicknames, so
-naming your packages like this means that users will have to type that entire
-giant name whenever they wanted to refer to a symbol without importing it, like
-`(com.stevelosh.cl-digraph.digraph:successors graph vertex)` instead of
-`(digraph:successors graph vertex)`.  This is just as miserable to read as it is
-to write.
-
-On the flip side: don't try to be overly clever and use a one or two letter name
-for your packages.  Common Lisp's packages are in a global namespace, and if
-more than one library tries to claim the same two-letter name it causes
-problems.  An example of this is Bordeaux Threads which has a package called
-`bt`.  It's too late to change this now, but try to avoid such easily-clashing
-names when making new packages.
-
-Another question that comes up is: "I see a lot of projects called `cl-whatever`
-— should I name my projects with the `cl-` prefix?".  Some Common Lispers hate
-the `cl-` prefix and never use it.  I personally prefer this style for two
-specific cases:
-
-* A Common Lisp wrapper around something else, like `cl-cudd` (not written by
-  me), which is a set of bindings to the TODO C++ CUDD library.
-* A Common Lisp implementation of a well-known data structure or protocol like
-  `cl-digraph`.
-
-Not using the `cl-` prefix in this case would feel confusing to me, because
-you'd just be calling the project `cudd` which would be easy to confuse with the
-actual library itself.
-
-For anything that's not one of these two cases I prefer to come up with a unique
-name instead.  Sometimes it's a pun or just something that sounds unique — the
-critical part is that it doesn't conflict with anything already in Quicklisp.
-
-When you *do* use the prefix, the next question is what parts of the project get
-the prefix.  This comes down to personal preference.  Here are my personal
-rules:
-
-* The project, Mercurial/Git repository, etc have the `cl-` prefix (e.g.
-  `https://github.com/sjl/cl-digraph`).
-* The system(s) should have the same name as the project, so it also gets the
-  prefix (e.g. `cl-digraph`).
-* The packages are going to be typed frequently, and we're *firmly* in Common
-  Lisp territory at the point where we're defining packages, so it's safe to
-  drop the prefix for packages (e.g. `digraph`).
-
-Other people (including my past and future selves) might disagree on some of
-these conventions.  Feel free to take them with a large grain of salt.
-
-### Common Libraries
-
-Common Lisp doesn't have a *large* of a community as some newer languages, but
-it still has a lot of libraries because it's had a community for a longer time.
-The stability of the core language means that libraries that were written in
-portable Common Lisp ten or twenty years ago can still run just fine.
-
-In this section I'll give you a quick overview of some of the more popular
-libraries you might run into as you learn the language.  You don't have to use
-all of them, of course, but it's helpful to have some idea of what's available.
-
-#### Alexandria
-
-[Alexandria][alexandria] is one of the most popular Common Lisp libraries (the
-name is a pun on the [Library of Alexandria][library-of-alex]), and it's
-a collection of all kinds of useful little utility functions like
-`read-file-into-byte-vector` and `map-permutations`.
-
-There are a *lot* of utility libraries for Common Lisp around — one rite of
-passage is building up your own personal utility library over time — but
-Alexandria is the most popular one.  Most projects with any dependencies at all
-will eventually end up with Alexandria in the dependency graph somewhere.
-
-#### Bordeaux Threads
-
-[Bordeaux Threads][bt] was mentioned earlier.  Threads aren't part of the Common
-Lisp standard, but most implementations provide their own custom interface for
-working with them.  Bordeaux Threads wraps all these implementation-specific
-interfaces and provides an API so you can write threaded code that will work
-portably.
-
-If you're looking for something like Java's `new Thread(() -> foo()).start();`,
-this is what you want.
-
-#### CFFI
-
-[CFFI][] is a foreign-function interface library that lets you load
-C libraries (e.g. `foo.dylib` or `foo.so`) and call the functions in them.  It
-works by wrapping implementation-specific interfaces, because this isn't part of
-the Common Lisp standard.
-
-Unfortunately it has the same name as Python's FFI library, so if you're
-searching for documentation make sure you're looking at the right version.
-
-#### CL-PPCRE
-
-[CL-PPCRE][ppcre] is an implementation of Perl-compatible regular expressions.
-If you're looking to use regular expressions in Common Lisp, this is what you
-want.
-
-#### Drakma
-
-[Drakma][] is an HTTP client.  If you need to make an HTTP request, this is what
-you want.  There are other HTTP clients around, but Drakma is commonly used and
-is fine for almost anything you might need.
-
-#### Iterate
-
-[Iterate][iterate] is a replacement for the `loop` macro.  It works similarly,
-but has a more Lispy syntax and a well-defined API for extending it with new
-iteration constructs.  I personally really like it, but beware: if you get used
-to `iterate` going back to vanilla `loop` will feel painful.
-
-#### local-time
-
-[local-time][] is a library for working with time and dates in Common Lisp.  The
-standard has some basic support for times built in, but if you want to do much
-calculation with times (including timezones) this is probably what you want.  If
-you're looking for something like [Joda Time][joda-time] in Common Lisp, this is
-as close as you're going to get.
-
-[joda-time]: http://www.joda.org/joda-time/
-
-#### lparallel
-
-[lparallel][] is a library that builds on top of Bordeaux Threads to make common
-parallel processing operations much easier.  Think of it as [GNU Parallel][] for
-Lisp, with a few extra features (e.g. channels and tasks).
-
-For example: if you've got a big vector you're mapping over with
-`(map 'vector #'work some-vector)` you can split it into chunks and
-run in multiple threads by changing it to
-`(lparallel:pmap 'vector #'work some-vector)`.
-
-[GNU Parallel]: https://www.gnu.org/software/parallel/
-
-#### Named Readtables
-
-[Named readtables][named-readtables] is a library that adds namespaces for
-readtables.
-
-One painful part of the standard is that reader macros are added and removed to
-the global readtable on the fly, so if you load multiple systems that define the
-same reader macros things can get messy.  Named readtables adds some much-needed
-hygiene to that process.  If you're working with reader macros at all you
-absolutely want to use this.
-
-#### Roswell
-
-[Roswell][] is a couple of things rolled into one.  It's a C program that
-handles installing and running multiple different Common Lisp implementations
-(kind of like [NVM](https://github.com/creationix/nvm) or
-[rvm](https://rvm.io/)), and it also provides a unified way to write small shell
-scripts in Common Lisp and compile them into binaries.
-
-I used Roswell for a little over a year, but I eventually stopped and now
-I personally don't think it's worth the trouble, for a couple of reasons.
-
-First: if you write portable code you generally don't need to worry running
-a particular version of an implementation, because Common Lisp is quite stable.
-I usually just install the latest version of each implementation I use with
-a package manager or by building from source.
-
-Second: after using it for a while I found that Roswell was always quite brittle
-to upgrade, and whenever things broke it would spew an almost JVM-sized stack
-trace without a decent error message.
-
-For me, the negatives outweighed the positives.  I'd personally recommend simply
-using the latest version of the implementations you care about and writing
-portable code.  For the compiling-into-binaries functionality I'd recommend
-using your implementation's built-in support for this, or using UIOP's wrapper
-around that, or using a separate library like Shinmera's [Deploy][].
-
-Of course your mileage might vary.  If you find yourself *really* needing to run
-specific versions of specific implementations in rapid succession, you should
-look into Roswell.
-
-[Deploy]: https://shinmera.github.io/deploy/
-
-#### SERIES
-
-[SERIES][series] was almost included in Common Lisp (it's in [Appendix A of
-CLtL2][series-cltl2]), but didn't quite make it.  It's a library for writing
-functional code that looks like the traditional `map` and `filter` and `reduce`
-operations but which compiles down to efficient loops.
-
-If you're looking for Clojure's transducers in Common Lisp, this is what you
-want.
-
-[series-cltl2]: https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node347.html
-
-#### st-json
-
-JSON support in Common Lisp is a god damn mess.  There are [an absurd number of
-JSON libraries][sabra] and I don't really *like* any of them.
-
-For me, the most important quality I need in a JSON library is an unambiguous,
-one-to-one mapping of types.  For example: some libraries will deserialize JSON
-arrays as Lisp lists, and JSON `true`/`false` as `t`/`nil`.  But this means `[]` and
-`false` both deserialize to `nil`, so you can't reliably round trip anything!
-
-I've settled on using [st-json][] and wrapping it up to be a little more
-ergonomic with some glue code.  It's not the fastest solution out there, but
-it's fine for my needs.  There are plenty of other options out there, so if you
-have different needs than me you should look into them.
-
-[sabra]: https://sites.google.com/site/sabraonthehill/home/json-libraries
-[st-json]: https://marijnhaverbeke.nl/st-json/
-
-#### usocket
-
-[usocket][] is a library for sockets.  Sockets and networking aren't part of the
-Common Lisp standard, but most implementations provide a custom interface for
-working with them.  usocket wraps the implementation-specific interfaces and
-provides an API so you can write networking code portably.
-
-If you want to make Lisp listen on a port and read streams of bytes from
-clients, or want to connect to a port and send raw bytes to it, this is what you
-want.
-
-[library-of-alex]: https://en.wikipedia.org/wiki/Library_of_Alexandria
-[alexandria]: https://common-lisp.net/project/alexandria/
-[iterate]: https://common-lisp.net/project/iterate/
-[series]: https://www.cliki.net/Series
-[bt]: https://common-lisp.net/project/bordeaux-threads/
-[gray]: https://www.cliki.net/Gray%20streams
-[flexi]: https://edicl.github.io/flexi-streams/
-[ppcre]: https://edicl.github.io/cl-ppcre/
-[uiop]: https://www.cliki.net/UIOP
-[usocket]: https://common-lisp.net/project/usocket/
-[drakma]: https://edicl.github.io/drakma/
-[lparallel]: https://lparallel.org/
-[local-time]: https://common-lisp.net/project/local-time/
-[named-readtables]: https://github.com/melisgl/named-readtables
-[Roswell]: https://github.com/roswell/roswell
-
-
-## Good Luck!
-
-I hope this whirlwind tour was useful.  Common Lisp is an old, deep language.
-It's not something you can learn in a month, but if you're willing to spend the
-time it will reward careful study.
-
-Feel free to email me or pop into IRC or Discord if you have questions.  Good
-luck!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/blog/2018/08/a-road-to-common-lisp.markdown	Sat Aug 04 12:57:08 2018 -0700
@@ -0,0 +1,1207 @@
++++
+title = "A Road to Common Lisp"
+snip = "One way to learn this old, deep language."
+date = 2018-07-03T16:00:00Z
+draft = false
+
++++
+
+I've gotten a bunch of emails asking for advice on how to learn Common Lisp in
+the present day.  I decided to write down all the advice I've been giving
+through email and social media posts in the hopes that someone might find it
+useful.
+
+<div id="toc"></div>
+
+## Context
+
+I think it's important to have a general sense of where Common Lisp came from
+and what kind of a language it is before you start learning it.  There are a lot
+of things that will seem very strange if you're coming straight from modern
+languages, but will make a lot more sense if you've got a bit of background
+context.
+
+### History
+
+Lisp and Common Lisp have a long, deep history.  I'm not going to try to cover
+it all here — if you're interested you should check out some of the following
+(in roughly increasing order of detail):
+
+* Wikipedia's [History of Lisp][wiki-history-lisp] and [History of Common Lisp][wiki-history-cl].
+* The [Where it Began section in Practical Common Lisp][pcl-history].
+* The [History: Where did Lisp come from?][cll-history] section of the comp.lang.lisp FAQ.
+* [Common Lisp: the Untold Story][untold] by Kent Pitman.
+* [The Evolution of Lisp][evolution] by Guy Steele and Richard Gabriel.
+
+I realize you probably won't want to read all of the links above immediately, so
+here's a whirlwind tour of sixty years of Lisp.
+
+Lisp began in the late 1950's.  It was invented by John McCarthy at MIT.
+
+Over the next twenty or so years various versions and dialects of Lisp grew and
+flourished.  Some of the more notable dialects were Maclisp, BBN Lisp/Interlisp,
+Franz Lisp, Spice Lisp, and Lisp Machine Lisp.  There were others too.  The
+point is that there were a *lot* of different implementations, all growing,
+changing, and trying out different things.
+
+(Scheme also originated in this time frame, but took a very different route and
+diverged from the path we're looking at.  I won't cover Scheme in this post.)
+
+In the early 1980s people decided that having a whole slew of
+mutually-incompatible dialects of Lisp might be not be the most desirable
+situation to be in.  An effort was made to take these different languages that
+had grown organically and produce one common language that would satisfy the
+needs of everyone.  In 1984 the first edition of Guy Steele's [Common Lisp: the
+Language][cltl] was published.
+
+If you do some math you'll see that at the time the book was published Lisp had
+around twenty-five years of real-world use, experimentation, experience, and
+history to draw upon.  Even so, the book alone didn't quite satisfy everyone and
+in 1986 a committee (X3J13) was formed to produce an ANSI specification for
+Common Lisp.
+
+As the committee worked on the standardization process, in 1990 the second
+edition of Common Lisp: the Language was published.  This was more comprehensive
+and contained some of the things the committee was working on (see the
+comp.lang.lisp FAQ linked above for more on this).  At this point the Lisp
+family of languages had over 30 years of experience and history to draw upon.
+For comparison: Python (a "modern" language many people think of as also being
+"kind of old") [was released][python] for the first time the following year.
+
+In 1992 the X3J13 committee published the first draft of the new ANSI standard
+for Common Lisp for public review (see Pitman's paper).  The draft was approved
+in 1994 and the approved specification was finally published in 1995.  At this
+point Lisp was over thirty-five years old.  The first version of Ruby [was
+released][rubby] in December of that year.
+
+That's the end of the history lesson.  There has not been another revision of
+the ANSI specification of Common Lisp.  The version published in 1995 is the one
+that is still used today — if you see something calling itself "an
+implementation of Common Lisp" today, that is the specification it's referring
+to.
+
+### Consequences
+
+So why am I telling you all this?  Because I want you to know what you're
+getting yourself into.  I want you to realize that Common Lisp is a stable,
+large, practical, extensible, ugly language.  Understanding these
+characteristics will make a lot of things make more sense as you learn the
+language.
+
+#### Escaping the Hamster Wheel of Backwards Incompatibility
+
+If you're coming from other languages, you're probably used to things breaking.
+If you want to run Ruby code written ten years ago on the latest version of
+Ruby, it's probably going to take some time to update it.  My current day job is
+in Scala, and if a library's last activity is more than 2 or 3 years old on
+Github I just assume it won't work without a significant amount of screwing
+around on my part.  The Hamster Wheel of Backwards Incompatibility we deal with
+every day is a fact of life in most modern languages (though some are certainly
+better than others).
+
+If you learn Common Lisp, this is not the case.  In the next section of this
+post I'll be recommending a book written in 1990.  You can run its code,
+unchanged, in a Common Lisp implementation released last month.  After years of
+jogging on the Hamster Wheel of Backwards Incompatibility I cannot tell you how
+much of a relief it is to be able to write code and reasonably expect it to
+still work in twenty years.
+
+Of course, this is only the case for the language itself — if you depend on any
+libraries there's always the chance they might break when you update them.  But
+I've found the stability of the core language is contagious, and overall the
+Common Lisp community seems fairly good about maintaining backwards
+compatibility.
+
+I'll be honest though: there are exceptions.  As you learn the language and
+start using libraries you'll start noticing some library authors who don't
+bother to document and/or preserve stable APIs for their libraries, and if
+staying off the Hamster Wheel is important to you you'll learn to avoid relying
+on code written by those people as much as possible.
+
+This may sound a little bleak, but it's made a bit better by some other
+characteristics of Common Lisp: it's a large, practical language.  The second
+edition of Common Lisp: the Language (usually abbreviated as "CLtL2" by Common
+Lisp programmers) is 971 pages long, not including the preface, references, or
+index.  When programming in Common Lisp people will tend to depend on
+a small(ish) number of libraries, and library writers often try to minimize
+dependencies by utilizing as much of the core language as possible.
+I personally try to stick to fewer than ten or so dependencies for my
+applications and no more than two or three for my libraries, but I'm probably
+a bit more conservative here than most folks (I *really* don't like the Hamster
+Wheel any more).
+
+It's also worth noting that since Common Lisp has been around and stable for so
+long, it has *libraries* older and more stable than many programming languages.
+For example: Bordeaux Threads (the de-facto threading library for Common Lisp)
+was first proposed in 2004 and released soon after (2006 at the latest but
+possibly earlier, it's hard to tell because so many links are dead now), which
+makes it fourteen years old.  So yes, threading is handled by a library, but I'm
+not worried about it breaking my code in the next decade or two.
+
+As you learn Common Lisp and look for libraries, try to suppress the voice in
+the back of your head that says "This project was last updated six years ago?
+That's probably abandoned and broken."  The stability of Common Lisp means that
+sometimes libraries can just be *done*, not *abandoned*, so don't dismiss them
+out of hand.
+
+#### Extensibility and Power
+
+Part of Common Lisp's practicality comes from its extensibility.  No one has
+been clamoring for a new version of the specification that adds features because
+Common Lisp gives users enough power to add new features to the language as
+libraries without having to alter the core language.
+
+Macros are what might come to mind when you hear "Lisp extensibility", and of
+course that's part of it.  Macros allow users to write libraries that would need
+to be core language features in other languages.
+
+Common Lisp doesn't include string interpolation.  You want it?  No problem, you
+don't have to wait for [Scala
+2.10](https://docs.scala-lang.org/overviews/core/string-interpolation.html) or
+[Python 3.6](https://www.python.org/dev/peps/pep-0498/), just [use
+a library][cl-interpol].
+
+Want to try some nondeterministic programming without any boilerplate?  [Grab
+a library][screamer].
+
+Pattern matching syntax can make for some really beautiful, readable code.
+Common Lisp doesn't include it, but of course [there's a library][trivia].
+
+Enjoying algebraic data types in Haskell or Scala?  Here's your [library][cl-adt].
+
+All of these libraries rely on macros to make using them feel seamless.  Of
+course you could *do* all of that without macros, but you've have to add a layer
+of boilerplate to manage evaluation.  This:
+
+    (match foo
+      '(list x y z) (lambda (x y z) (+ x y z))
+      '(vector x y) (lambda (x y) (- x y)))
+
+just doesn't flow off the fingers like:
+
+    (match foo
+      ((list x y z) (+ x y z))
+      ((vector x y) (- x y)))
+
+No one's up in arms trying to get a new revision of the Common Lisp standard to
+add pattern matching because you can write it as a library and get 95% or more
+of what you've get if it were built in.  The language gives you enough power to
+extend it in a way that feels like the extension was there from the beginning.
+
+Macros are one of the things that make Lisp so incredibly extensible, because
+they let you transform arbitrary code into other arbitrary code.  This is true
+for macros in languages like C too, but Common Lisp macros are fundamentally
+different because they're *part of the language*.
+
+In C you have a layer of macros on top, written in a separate preprocessor macro
+language.  The macro layer and the language layer are separate from each other,
+with the macro layer providing one one extra level of abstractive power.
+
+In Common Lisp, you write macros *in Common Lisp itself*.  You can then use
+those macros to write functions, and use those functions to write more macros.
+Instead of two stratified layers it's a *feedback loop* of abstractive power.
+
+But macros aren't the only thing about Common Lisp that make it so practical and
+extensible.  Something that people often don't realize is that while Common Lisp
+is an extremely high-level language thanks to macros, it also has plenty of
+low-level facilities as part of the language.  It's never going to be as
+low-level as something like C or Rust, but you might be surprised at some of the
+things that the ANSI spec includes.
+
+Want to see the assembly that a particular function compiles down to?
+[`DISASSEMBLE`][dis] it!
+
+Want to stack-allocate something to avoid some garbage collection?  X3J13
+[thought of that][dynext].
+
+Need arrays of unboxed floats to ship to a graphics card?  [The standard allows
+for that][arrays].
+
+Think `GOTO` should be considered helpful, not harmful?  Well okay, we're all
+adults here.  [Good luck][tagbody], try not to shoot your foot off.
+
+Need to do unsigned 8-bit arithmetic in your Game Boy emulator, but would prefer
+it to compile down to just a machine instruction or two?  [It's
+possible][arith].
+
+Not all Common Lisp implementations actually perform all these optimizations,
+but the designers of Common Lisp had the foresight to include the language
+features needed to support them.  You can write vanilla Common Lisp as defined
+by the standard and trust that it will run everywhere, and implementations that
+*do* support these kinds of things will take advantage of the optimization
+opportunities.
+
+This combination of supporting extremely high-level programming with macros and
+a reasonable amount of low-level optimization mean that even though the
+specification is over twenty years old, it's still a good solid base to build on
+today.  The thirty years of experience and history the designers were drawing
+from allowed them to create a very practical language that has survived for
+decades.
+
+#### Ugliness
+
+It's also important to realize that while Common Lisp might be incredibly
+practical, the need to accommodate existing users and dialects means that there
+are ugly parts.  If you buy a paper copy of the second edition of Common Lisp:
+the Language and look up "kludges" in the index you'll find this:
+
+[![Photo of a page of CLtL2's Index, listing "kludges" as pages 1 to 971](/media/images/blog/2018/07/lisp-kludge.jpeg)](/media/images/blog/2018/07/lisp-kludge.jpeg)
+
+Common Lisp is not a beautiful crystal of programming language design.  It's
+a scruffy workshop with a big pegboard wall of tools, a thin layer of sawdust on
+the floor, a filing cabinet in the office with a couple of drawers that open
+perpendicular to the rest, and there's a weird looking saw with `RPLACD` written
+on the side sitting off in a corner where no one's touched it for twenty years.
+
+This historical baggage is a price paid to ensure Common Lisp had a future.  It
+made it practical for people using the old dialects to actually adopt Common
+Lisp with a reasonable amount of effort.  If the designers had tried to make it
+perfect and beautiful this could have made it too different to port
+implementations and code to and might have resulted in the language being
+ignored, instead of being adopted and embraced.
+
+[wiki-history-cl]: https://en.wikipedia.org/wiki/Common_Lisp#History
+[wiki-history-lisp]: https://en.wikipedia.org/wiki/Lisp_(programming_language)#History
+[cll-history]: https://www.cs.cmu.edu/Groups//AI/lang/lisp/faq/lisp_2.faq
+[pcl-history]: http://www.gigamonkeys.com/book/introduction-why-lisp.html#where-it-began
+[untold]: http://www.nhplace.com/kent/Papers/cl-untold-story.html
+[evolution]: https://www.dreamsongs.com/Files/HOPL2-Uncut.pdf
+[cltl]: https://www.cs.cmu.edu/Groups/AI/html/cltl/cltl2.html
+[python]: https://en.wikipedia.org/wiki/History_of_Python#Early_history
+[rubby]: https://en.wikipedia.org/wiki/Ruby_(programming_language)#First_publication
+[bt-release]: https://web.archive.org/web/20040831185622/http://ww.telent.net/diary/2004/7/#9.57181
+[cl-interpol]: https://edicl.github.io/cl-interpol/
+[screamer]: https://nikodemus.github.io/screamer/
+[trivia]: https://github.com/guicho271828/trivia/wiki/What-is-pattern-matching%3F-Benefits%3F
+[cl-adt]: https://github.com/tarballs-are-good/cl-algebraic-data-type
+[dis]: http://clhs.lisp.se/Body/f_disass.htm
+[dynext]: http://clhs.lisp.se/Body/d_dynami.htm
+[arrays]: http://clhs.lisp.se/Body/15_ab.htm
+[arith]: https://pdfs.semanticscholar.org/7089/0eff0e93aba49174a9346731f4bf9225706d.pdf
+[tagbody]: http://clhs.lisp.se/Body/s_tagbod.htm
+
+## A Road to Learning Common Lisp
+
+If all of this hasn't scared you away from the language, let's talk about how
+you can learn it in 2018.
+
+If you search around on the internet for Common Lisp tutorials and guides,
+you're not going to find as much as you might expect.  This is because a lot of
+Common Lisp reference material was created before and/or during the infancy of
+the internet.  There are a *lot* of books about Common Lisp out there.  Some are
+better than others.  I'll recommend the ones I personally think are the best,
+but don't hesitate to browse around and find others.
+
+One final disclaimer: this is *a* road to Common Lisp, not *the* road to Common
+Lisp.  It's what I followed (without some of the dead ends) and has a lot of my
+personal opinions baked in, but is by no means the only way to learn the
+language.  Ask around and get some more opinions — more options won't hurt!
+
+### Get a Lisp
+
+To get started with Common Lisp you'll need to install a Common Lisp
+implementation.  Remember: Common Lisp is an ANSI specification, so there are
+multiple implementations of it, which gives you choices.  There are a bunch of
+options, but I'll make it simple for you:
+
+* If you're comfortable with the command line, installing packages with a package manager, and already have a text editor you like, choose [SBCL][].
+* Otherwise, choose [ClozureCL][CCL] (often called "CCL").
+
+That's Clozure with a Z.  Clojure is something entirely different that just
+happens to have a confusingly similar name.
+
+You might also hear of something called CLISP, which sounds like it might be
+what you want.  It's not.  CLISP is just another implementation, but it hasn't
+had a release in eight years (even though development is still ongoing in its
+source repos) and it's not as commonly used as CCL or SBCL, so it'll be harder
+to find help if you have questions about the installation, etc.
+
+You might also hear about something called Roswell.  Don't use Roswell, you don't
+need it (yet (or at all)).
+
+Just install SBCL or CCL for now, you can explore the other options once you've
+got your bearings a bit better.
+
+### Pick an Editor
+
+You might hear people tell you that you *must* learn Emacs before learning
+Common Lisp.  They're wrong.  You can get started learning the language just
+fine in whatever text editor you're comfortable in.
+
+If you don't have a preference, CCL itself comes bundled with a text editor on
+MacOS.  That one will work just fine to start.
+
+Emacs, Vim, Sublime Text, Atom, whatever, for now it doesn't matter.  As long as
+it can balance parenthesis and highlight comments and strings, that's all you
+need to start.  Worry about shaving the editor yak once you're more comfortable
+in the language.
+
+### Hello, Lisp
+
+To check that you've got everything set up properly, make a `hello.lisp` file
+with the following contents:
+
+```lisp
+(defun hello ()
+  (write-line "What is your name?")
+  (let ((name (read-line)))
+    (format t "Hello, ~A.~%" name)))
+```
+
+Don't worry about what this means yet, it's just a check that everything's
+working properly.
+
+Open an SBCL or CCL REPL and load the file by entering `(load "hello.lisp")`,
+then call the function and make sure it works.  It should look something like
+this if you picked SBCL:
+
+    $ sbcl
+    * (load "hello.lisp")
+
+    T
+    * (hello)
+    What is your name?
+    Steve
+    Hello, Steve.
+    NIL
+    *
+
+Or this if you chose CCL (the program might be annoyingly named `ccl64` if
+you're on a 64-bit system):
+
+    $ ccl64
+    Clozure Common Lisp Version ...
+
+    ? (load "hello.lisp")
+    #P"/home/sjl/Desktop/hello.lisp"
+    ? (hello)
+    What is your name?
+    Steve
+    Hello, Steve.
+    NIL
+    ?
+
+If your arrow keys and backspace don't work in the REPL, use [`rlwrap`][rlwrap]
+to fix that.  `rlwrap sbcl` will give you a non-miserable REPL.  `rlwrap` is
+a handy tool to have in your toolbox anyway.
+
+[rlwrap]: https://github.com/hanslub42/rlwrap
+
+### A Gentle Introduction
+
+The best book I've found for getting started in Common Lisp is [Common Lisp:
+A Gentle Introduction to Symbolic Computation][book-gentle].  This book really
+does strive to be gentle.  Even if you've programmed before I'd recommend
+starting here because it eases you into the language.  If you find it's moving
+too slow just skim forward a bit.
+
+The 1990 edition is available free from the site, and there's a 2013 reprint
+which fixes some minor errors in the 1990 version.  If you can afford it I'd
+recommend buying the 2013 edition, but the 1990 version will also do fine.
+
+Go through the book and *do all the exercises*.  This will take a while.
+
+This is mainly meant to get you started overcoming some of the main obstacles to
+being comfortable in Common Lisp, like:
+
+* How am I ever going to remember all these weird function names?
+* Why do people use strings so rarely?
+* When do I need/not need the goddamned quotation mark?
+
+You should also join the `#clnoobs` channel on Freenode so you can ask questions
+if you get stuck.  For the most part people there are friendly and helpful,
+though I'll warn you in advance that there's at least one person who can
+sometimes be abrasive.
+
+If IRC isn't your thing there's also a [Discord
+server](https://discord.gg/tffeu2x) that some of us hang out in.  Join the
+`#common-lisp` channel there and we'll be happy to help you.
+
+[book-gentle]: https://www.cs.cmu.edu/~dst/LispBook/
+[SBCL]: http://www.sbcl.org/on
+[CCL]: https://ccl.clozure.com/
+
+### Getting Practical
+
+Once you've finished that book the next one you should attack is [Practical
+Common Lisp][book-pcl].  You can get a paper copy if you want, but the full book
+is available on the site.
+
+You can skip the editor/programming environment part because the environment it
+recommends (Lisp in a Box) is abandoned and no longer works.  Just keep using
+the programming environment you're comfortable with for now.
+
+Unfortunately the book doesn't include exercises.  If you *really* want to get
+the most out of it you can type in all the code as you're reading it and poke at
+it, but if you've already done the exercises in the previous book it's probably
+safe to just sit down and read the book carefully.
+
+Make sure you understand everything as you go through the book.  Don't be afraid
+to ask questions on IRC or Discord (or email me if you want, I don't mind) if
+something's not clear.
+
+You should also begin to get comfortable looking up things in [the Common Lisp
+language specification][clhs] itself.  It's the ultimate manual for Common Lisp.
+It can be pretty dense at points, but can answer many questions you might have.
+You can either use the index page to find what you're looking for or just search
+on Google for "clhs whatever".  CLHS stands for "Common Lisp HyperSpec", which
+is the hyperlinked, HTML version of the spec.
+
+(Some people will tell you to learn the language by just reading the spec.  That's
+ridiculous — it's like trying to learn French by reading a dictionary.  It's
+a useful tool to have, but not the only one you'll need.)
+
+[book-pcl]: http://www.gigamonkeys.com/book/
+[clhs]: http://www.lispworks.com/documentation/lw70/CLHS/Front/Contents.htm
+
+### Make Something
+
+Once you've got those two books under your belt and some practice using the
+spec, it's time to make something without someone holding your hand.  It doesn't
+have to be anything big or special, the goal is to just write some Lisp without
+having the answer on the next page.
+
+If you need some ideas:
+
+* Do some [Project Euler](https://projecteuler.net/) problems.
+* Do some [Advent of Code](https://adventofcode.com/) exercises.
+* Make a [stupid Twitter bot](https://twitter.com/git_commands).
+* Make a personal calendar program that records your appointments, checks the
+  weather forecast the day of, etc.
+
+It doesn't really matter what you make, just make *something* on your own.
+
+### Lisp as a System
+
+At this point it's time to take your Common Lisp skills up a notch.  Up until
+now I've told you to just use any text editor because it's more important to get
+you some experience with the language, but now it's time to move on.
+
+In most languages the development process looks something like this:
+
+1. Edit some code in the project with an editor.
+2. Compile the project (some languages skip this step).
+3. Run the project (or the tests).
+4. Observe the output (in the console, a browser, etc).
+5. Go to 1.
+
+This is not how most Common Lisp users interact with the language.  In Common
+Lisp, the development cycle looks more like this:
+
+1. Start a Lisp process.
+2. Load the project.
+3. Edit some code with your editor.
+4. Tell the running process to compile *only the code you edited*.
+5. Interact with the changed code in the process via the REPL, an HTTP request, etc.
+6. Observe the output (either in the console, a browser, etc).
+7. Go to 3.
+
+When you embrace the Lisp way of working you'll rarely recompile and reload an
+entire project.  Usually you'll write a function (or a macro, or parameter, or
+whatever), compile just that function, maybe poke at it in the REPL a bit, and
+then move on to the next function.  This has some advantages over the
+traditional compile-everything-then-run approach.
+
+First: compiling a small chunk of code is fast.  I just timed compiling a few of
+the larger functions in one of my projects and they took around 50-80
+microseconds.  You don't have to wait for the compiler, so your
+concentration/thought process never has time to wander.
+
+Another advantage is that when you get back the results of your compilation,
+any errors or warnings you receive are almost certainly related to the few
+lines of code you just compiled.  If you compile a ten-line function, run it,
+and get a division by zero error you can immediately focus in on the ten lines
+you just compiled and think about what changed.
+
+Because the Lisp process is always running, as soon as you compile a function
+it's ready to be used in the REPL.  You can throw some arbitrary data at it and
+inspect the results to see how it behaves in isolation before you build more
+things on top of it.
+
+This cycle of making a function, compiling it, poking at it to make sure it's
+working as expected, and moving on happens *constantly*.
+
+In contrast, when working in languages like Scala or Python I almost never find
+myself writing one single function and compiling or running the project
+immediately.  Spinning up the compiler or running the unit tests takes at
+*least* a second or two (or, sometimes *minutes* in Scala, unfortunately) so to
+avoid having a constant stream of gaps in my thought I end up writing a bunch of
+functions at once, and then I run the project or tests once I know they have
+a chance of working.
+
+But then when I get back an error I have much more surface area to check,
+because I've added a lot of new code!  So now I have to track down a problem
+that might be in something I wrote four minutes ago, whereas in Lisp I would
+only have to ever look at the code I wrote in the last few seconds.
+
+I've started using IntelliJ with Scala to help make this a bit less painful.  It
+does help with the compile times because it recompiles things on the fly, but it
+doesn't solve the rest of the problem.  I can write a Scala function in IntelliJ
+and it will be compiled immediately, but I can't *interact* with it immediately
+like I can in Common Lisp.
+
+When you work in this style with Common Lisp I think you'll really grow to love
+it.  Writing in other languages will begin to feel like shipping your code off
+to the DMV and getting it back a week with a page full of red ink somewhere in
+the hundred forms you filled out.  Writing in Common Lisp feels like interacting
+with a living, breathing organism, or like [teaching things to an eager
+assistant][eager].
+
+This goes beyond just the short feedback loop and interactive REPL, too.  As an
+example, imagine you're making a video game and have a bug somewhere in your
+damage calculation that will occasionally cause a division by zero.  Now let's
+say you're working on the code for a particular quest.  You'll start the game,
+load a save file at the beginning of the quest, and start going through the
+steps.  All of a sudden, in the middle of killing the final monster for the
+quest, you hit the damage bug!  In traditional languages, one of two things
+might happen:
+
+1. The game crashes, and you get a stack trace and maybe a core dump.
+2. You've wrapped a `try` block around the main game loop that logs a stack
+   trace and ignores errors and allows the game to continue.
+
+Case 1 is pretty bad.  You've got to try to track down the bug from a snapshot
+of what things looked like at the time (the stack trace and core dump).  And
+even if you manage to fix it, now you've got to redo all that playing to get
+back to testing your quest code that you were originally working on.
+
+Case 2 is bad, in a different way.  If you just ignore errors all the time, the
+game might now be in a weird state.  You also might lose some critical context
+that's necessary to debug the problem, unless you're also saving a core dump
+(but I don't know of many people who do that).
+
+In Common Lisp you can certainly choose to panic or ignore on errors, but
+there's a better way to work.  When an error is signaled in Common Lisp, it
+doesn't unwind the stack.  The Lisp process will pause execution at that point
+and open a window in your editor showing you the stack trace.  Your warrior's
+sword is hovering at the monster, waiting for you.  At this point you can
+communicate with the running process at the REPL to see what's going on.  You
+can examine variables in the stack, or even run any arbitrary code you want.
+
+Once you figure out the problem ("Oh, I see, the `calculate-armor-percentage`
+function returns `0` if a shielding spell ran out during the same frame") you
+can fix the code, recompile the problematic function, and *restart the execution
+of that function in the call stack*.  Your warrior's sword lands, and you move
+back to what you were doing before.
+
+You don't have to track down the bug from just a stack trace, like a detective
+trying to piece together what happened by the blood stains on the wall.  You can
+examine the crime *as it's happening* and intervene to save the victim.  It's
+like if you could run your code in a debugger with a breakpoint at every single
+line that only activates if something goes wrong!
+
+Maybe you don't make video games.  But this process can be useful in all kinds
+of contexts.  Maybe you're writing a web app that talks to an API somewhere, and
+are debugging a request that fails somewhere between two calls to the API, e.g.
+between "create widget `foo`" and "add `foo` to widget list `bar`".  Instead of
+just aborting the request, logging a stack trace, and now leaving things in
+a possibly weird state (`foo` having been created without being in the expected
+`bar` list), you can fix the problem and allow the request to finish properly.
+
+Of course this won't always work.  If you've got a big function that does some
+side effects and then crashes, restarting execution of the function would make
+the side effects happen again.  But if you divide up your functions well ([one
+function to a function!][1ftaf]) this case is pretty rare.  And even when it
+does happen, it just means you're back in the same situation you're in *by
+default* with other languages!
+
+[eager]: https://www.reddit.com/r/lisp/comments/4oo1cp/common_lisp_for_clojure_programmer/d4eec68/
+[1ftaf]: https://groups.google.com/forum/message/raw?msg=comp.lang.lisp/9SKZ5YJUmBg/Fj05OZQomzIJ
+
+### Learning Paradigms
+
+### Recipes for Success
+
+## Where to Go From Here
+
+If you made it through all the books and activities in the previous section:
+congratulations, you're off to a great start!  Now that you've got a decent
+handle on the core language you can explore in many different directions,
+depending on your interests.
+
+### Macros
+
+If you want to learn the secrets of macros, you'll probably want to read and
+work through [On Lisp][] and [Let Over Lambda][] (in that order).
+
+I'll say that you should take both books (*especially* the latter) with a large
+grain of salt.  A lot of Common Lisp users don't agree with all of the arguments
+and style in these books, but I think they can still provide plenty of value if
+you read them with a critical mind.
+
+[On Lisp]: http://www.paulgraham.com/onlisp.html
+[Let Over Lambda]: https://letoverlambda.com/
+
+### Object-Oriented Programming with CLOS
+
+Common Lisp has some very sophisticated support for Object-Oriented Programming
+through CLOS.  If you have bad memories of OOP from working in a Java cube farm
+like I did, I'd urge you to give CLOS a fair chance to change your mind.
+
+Start with [Object-Oriented Programming in COMMON LISP: A Programmer's Guide to
+CLOS][Keene] — it's a wonderfully-written, short and to-the-point book that will
+give you a good overview of how CLOS is intended to be used.
+
+If you really want to bend your mind, try [The Art of the Metaobject
+Protocol][amop] (usually abbreviated as AMOP).  This book will probably take you
+a couple of tries to get through.  Read it until you hit a mental wall, go work
+on other things for a couple of months, and come back and try again.  Repeat
+that process as many times as necessary.
+
+[Keene]: https://www.amazon.com/Object-Oriented-Programming-COMMON-LISP-Programmers/dp/0201175894
+[amop]: https://www.amazon.com/Art-Metaobject-Protocol-Gregor-Kiczales/dp/0262610744
+
+### Low-Level Programming
+
+Low-level programming can mean a lot of different things.
+
+If you're interested in writing emulators for old computers, I wrote [a series
+of posts][chip8posts] on making a [CHIP-8][] emulator in Common Lisp.
+[cl-6502][] is an emulator for the processor used in the NES (and lots of other
+things) and has a really nice [literate programming][cl-6502-book] version
+that's wonderful to read through.
+
+If you want to interface with C libraries, [CFFI][] is what you want to use.
+The manual is worth reading, though I wish it were a little gentler to start
+with.
+
+[chip8posts]: http://stevelosh.com/blog/2016/12/chip8-cpu/
+[CHIP-8]: https://en.wikipedia.org/wiki/CHIP-8
+[cl-6502]: https://github.com/kingcons/cl-6502
+[cl-6502-book]: http://redlinernotes.com/docs/cl-6502.pdf
+[CFFI]: https://common-lisp.net/project/cffi/
+
+### Web Development
+
+Unfortunately I don't have too many suggestions for web development in Common
+Lisp.  I've made a conscious effort to avoid web development in the past five or
+so years, because it seems like the Hamster Wheel of Backwards Incompatibility
+has become more of a Hamster Centrifuge in that field.
+
+There is a `#lispweb` channel on Freenode and a `#webdev` channel in the Lisp
+Discord, so if you have questions you could start by asking there.  Those
+channels are a bit less populated than the other Lisp channels, so don't expect
+an answer immediately.
+
+### Game Development
+
+Common Lisp has a small but enthusiastic community of people who like making
+games.  There's a `#lispgames` channel on Freenode and a `#gamedev` channel on
+the Lisp Discord that you should join if you're interested.
+
+[Land of Lisp](http://landoflisp.com/) is a fun little book to go through.  The
+coding style in the book has some... "eccentricities", which is why I don't
+recommend it as a first book on Lisp (e.g. using `ash` instead of `truncate` or
+`floor` for integer division), but if you know the language and just want to get
+started making some simple games I think you'll enjoy working through it.
+
+If you want an excuse to make a game in Lisp in a week, the Lisp Game Jam is
+something you can join.  It's usually held once or twice each year, so you'll
+have to search around (or ask in `#lispgames`) to find out when the next one is.
+
+Lisp doesn't have any engine as full-featured as Unity, but several people are
+currently working on making 3D game engines.  Ask around to see what people are
+using these days.  Unfortunately a 3D game engine will generally need to
+interface with the OS to render images and produce audio, and so can't be
+written in pure Common Lisp.  This means that some running on the Hamster Wheel
+of Backwards Incompatibility will be necessary to keep up with OS changes (e.g.
+[Apple deprecating OpenGL][eat-shit-apple]).
+
+If you're interested in old-school ASCII/tile-based games, I've personally done
+some work with using [ncurses][] and [bearlibterminal][] in Common Lisp.
+There's something really fun about making a game people can play over telnet!
+Feel free to get in touch with me if you're interested in that kind of stuff and
+want to know more.
+
+[eat-shit-apple]: https://www.macrumors.com/2018/06/05/apple-deprecates-opengl-opencl-gaming/
+[ncurses]: https://github.com/HiTECNOLOGYs/cl-charms
+[bearlibterminal]: http://foo.wyrd.name/en:bearlibterminal
+
+### Window Management
+
+If you're running Linux and like tinkering with your desktop environment,
+[StumpWM][] is an X window manager written in Common Lisp.  I've just recently
+switched back to Linux so I've only been using it for a month or so, but it's
+really pleasant to be able to customize my working environment with Common Lisp.
+
+StumpWM has a small but friendly community — if you're looking for a non-trivial
+open source Common Lisp project to contribute to, StumpWM would be a great
+choice.
+
+[StumpWM]: https://stumpwm.github.io/
+
+### Unit Testing
+
+If you're coming from a modern language, especially one with a lot of
+"test-driven development" advocates, you might be surprised at the lack of an
+emphasis on unit testing in Common Lisp.  I think one reason for this is that in
+some languages a unit test is the simplest way to actually *run* a function,
+but Lisp's interactive style of development gives you an even easier
+alternative: just run the function in the REPL!
+
+Despite the lack of heavy unit testing in the community, there are almost as
+many unit testing *frameworks* as there are Common Lisp programmers!  This is
+probably because making a unit testing framework is so easy with a few macros.
+I personally love [1am][], but there are *plenty* more to choose from.
+
+Whichever one you choose, please make sure to be a good citizen and create
+a separate ASDF system for your unit tests, so people can use your library
+without having to load Yet Another Testing Framework.
+
+[1am]: https://github.com/lmj/1am
+
+## Modern Common Lisp
+
+Common Lisp is old and stable, but that doesn't mean it's stagnant.  The
+language gives you plenty of power to build on, and before I wrap this up I want
+go over a couple of things that often trip up new people.
+
+### Structure
+
+Common Lisp's terminology for various parts of projects is often confusing to
+new people because it's old and uses a lot of words that we use now (like
+“package”) to mean different things than people mean today. Things get easier
+once you internalize what Common Lisp means by the terms.
+
+NOTE: I posted a quick-and-dirty version of this section as a [comment][] on Lobste.rs
+while I was waiting for a plane — this section of the post is an expanded
+version of that comment.
+
+[comment]: https://lobste.rs/s/fwhuz5/my_lisp_journey_1_getting_started_with#c_ebhvzq
+
+#### Packages
+
+We often see questions in `#clnoobs` that look something like: "How do I export
+a class from a package"?  Questions worded like this are a sign of a very common
+misunderstanding about what packages in Common Lisp *actually are*.
+
+A package in Common Lisp is **a container for symbols**.  That's it.  They're
+a way to group related names (symbols) together so you don't have to do the
+miserable prefixing of every name with `mylibrary-...` like you need to do in
+Emacs Lisp or C to avoid name clashes.
+
+You don't export a class from a package, you export a *symbol*.  You don't
+import a function, you import the *symbol* it's attached to.  This sounds
+pedantic, but is important to keep clear in your head as you start using the
+package system.  If you're not clear on what exactly a symbol *is*, I wrote
+a [separate post][symbols] just about symbols which you might find helpful.
+
+Another major tripping point for new people is the relationship between packages
+and files.  Or, rather, the completely *lack* of any relationship in Common
+Lisp.
+
+In many languages like Python, Java, or Clojure, a file's package and its
+location on the hard drive are tied together.  For example: when you say `import
+foo.bar.baz` in Python, Python will look for a `baz.py` inside the `foo/bar/`
+folder (it's a little more complicated than this, but that doesn't matter for
+this example).
+
+In Common Lisp, this is not the case.  **Files and packages are completely
+orthogonal in Common Lisp.**  You can have many files that all work in the same
+package, or one file that switches between many packages, or even create or
+modify packages at runtime.
+
+This gives you maximum flexibility to work however you want.  For example: in my
+[Prolog VM][temperance] most of the packages are each defined in their own file,
+much like you would do in modern languages.  But the `temperance.compiler` TODO
+package is pretty large (the compiler is the most complicated part of the code)
+and so I split it into [a series of separate files][temperance-compiler], each
+one dealing with a single pass of the compiler, which all work in the same
+package.
+
+So if files and packages aren't related, the next question is: how does Common
+Lisp know where to *find* anything on disk when it comes time to load the code?
+
+[symbols]: TODO
+[temperance]: TODO
+[temperance-compiler]: TODO
+
+#### Systems
+
+A system in Common Lisp is a collection of serveral things:
+
+* The code.
+* A description of how to load that code.
+* A list of other systems this system depends on, which need to be loaded prior
+  to loading this one.
+* Some metadata like author, license, version, homepage, etc.
+
+The Common Lisp language itself has no knowledge of systems.  If you look at
+chapter TODO of CLtL2 you'll see that it was imagined that each library author
+would write their own custom file to load their code.
+
+Of course, since Common Lisp gives you the power to abstract almost anything,
+people eventually abstracted the process of loading Common Lisp code.
+
+ASDF is a Common Lisp library bundled with most (all?) modern implementations
+which handles defining and loading systems.  The name ASDF stands for "Another
+System Definition Facility", so as you might guess there have been several other
+such libraries.  ASDF is the one everyone uses today.
+
+ASDF standardizes the process of defining a system into something like this:
+
+* The system definition(s) for a project called `foo` would be in a file named `foo.asd`.
+* Each system is defined with a `(defsystem ...)` form inside this file.
+
+We'll talk more about what a "project" is shortly.  Note the extension of the
+file is `asd`, not `asdf`, which is a little confusing, but was probably chosen
+to work in environments with three-letter-extension limits.
+
+The [ASDF manual][TODO] is the definitive resource for the syntax and semantics
+of `defproject`, but can be a little heavy to read if you're just getting
+started.  Another way to get started is to read some `.asd` files of some
+small-to-medium sized open source projects and see how they handle things.
+
+Systems and packages are orthogonal in Common Lisp.  Some systems (like small
+libraries) will define exactly one package.  Some systems will define multiple
+packages.  Rarely a system might not define any new packages, but will use or
+add to an existing one.
+
+For example:
+
+* My directed graph library [cl-digraph][] contains a system called `cl-digraph`.
+* That system has a description of how to load the code, which lives in the [`cl-digraph.asd`][cl-digraph-asd] file.
+* As part of loading the system it will load the file [`packages.lisp`][cl-digraph-packages], which creates a package called `digraph`.
+
+Even though ASDF standardizes some aspects of system definition, it still gives
+you plenty of flexibility.  As you read projects by different authors you'll
+encounter different ways of organizing systems — this can be a little
+overwhelming at first, but it means you can organize a system in the way that
+works *best for that system*, which is really nice once you've got some
+experience under your belt.
+
+One example of this is how people define packages for their systems.  There are
+a couple of common ways to do this you'll see in the wild:
+
+* A single `package.lisp` file which contains all the definitions for all the
+  packages in the project, and gets loaded before all other files.  This is the
+  strategy I usually prefer.
+* Each file defines its package at the top of the file, much like you would in
+  Clojure or other modern languages.  Care is taken in the system definition to
+  load the files in the correct order so that each package is defined before it
+  is ever used.
+
+So to recap: a system is a collection of code and a description of how to load
+it, a list of its dependencies, and some metadata.  Now let's move up one level
+higher to the final layer of structure you need to know about.
+
+[cl-digraph]: TODO
+[cl-digraph-asd]: TODO
+[cl-digraph-packages]: TODO
+
+#### Projects
+
+A project in Common Lisp is not an official term defined anywhere that I know
+of, but is a word that's generally used to mean something like a library,
+a framework, an application, etc.
+
+A project will usually define at least one system, because systems are where you
+describe how to load the code, and if a project didn't define a system how would
+you know how to load its code?  My cl-digraph library mentioned above is
+a project that defines *three* systems:
+
+The `cl-digraph` system contains the actual data structure and API.  It has no
+dependencies.
+
+The `cl-digraph.test` system contains the unit tests.  It depends on the
+`cl-digraph` system (because that's the code it's going to test) and the `1am`
+system (a unit test framework).  I made this a separate system because it allows
+users to load the main code without also having to load the unit testing
+framework if they're not going to be running the tests.
+
+The `cl-digraph.dot` system contains code for drawing the directed graphs to
+image files with [Graphviz][TODO].  It depends on the `cl-digraph` system and
+the `cl-dot` system (the Graphviz bindings).  I made this a separate system
+because it allows users load the main code without also having to load the
+Graphviz bindings if they don't care about drawing.
+
+If I were writing this project today I'd use a forward slash in the system names
+instead of a period (e.g. `cl-digraph/test`), because ASDF has some nice [extra
+support][TODO] for that.  I just didn't know about it at the time, and don't
+want to break backwards compatibility now.
+
+We saw how Common Lisp has no concept of a system — that concept comes from
+ASDF.  Similarly, ASDF has no concept of the internet or of reaching out to
+somewhere to download things.  ASDF assumes you have somehow acquired the
+systems you want to load and stored them on your hard drive, perhaps by sending
+a check to an address and receiving a copy of the code on floppy disk, as many
+of my old Lisp books offer in their final pages.
+
+Quicklisp is another library that works on top of ASDF to provide the "download
+projects from the internet automatically if necessary" functionality that people
+expect in the modern world.  So when you say `(ql:quickload :cl-digraph)` you’re
+asking Quicklisp to download cl-digraph (and any dependencies) if necessary, and
+then hand it off to ASDF to actually load the code of the `cl-digraph` system.
+Unlike ASDF, Quicklisp is relatively new in the Common Lisp world (it's only
+about eight years old) and so is not bundled with any modern Lisp
+implementations that I know of (yet?), which is why you need to install it
+separately.
+
+#### Recap
+
+Here's a quick recap of the different layers of project structure you'll
+encounter in Common Lisp:
+
+* **Files** are files on your hard drive.
+* **Packages** are containers of symbols. They are orthogonal to files.
+* **Systems** are collections of code, instructions on how to load this code,
+  dependency lists, and metadata. They are orthogonal to packages.
+* **Projects** are high-level collections of... "stuff" such as code,
+  documentation, maybe some image assets, etc. They are (mostly) orthogonal to
+  systems (are you seeing a trend here?).
+* Common Lisp itself knows about files and packages.
+* ASDF adds systems.
+* Quicklisp adds the internet.
+
+#### Naming Conventions
+
+One more small thing we should talk about before moving on is how to name
+things.  This section is only my personal opinion, so some other folks will
+probably disagree.  You should consider their arguments and your own needs and
+decide for yourself.
+
+You can name your packages anything you want, but your users will thank you if
+you follow a couple of simple rules.  First, don't do the overly-verbose style
+of naming packages like `com.stevelosh.cl-digraph.digraph`.  Unfortunately
+Common Lisp doesn't have a portable way to add package-local nicknames, so
+naming your packages like this means that users will have to type that entire
+giant name whenever they wanted to refer to a symbol without importing it, like
+`(com.stevelosh.cl-digraph.digraph:successors graph vertex)` instead of
+`(digraph:successors graph vertex)`.  This is just as miserable to read as it is
+to write.
+
+On the flip side: don't try to be overly clever and use a one or two letter name
+for your packages.  Common Lisp's packages are in a global namespace, and if
+more than one library tries to claim the same two-letter name it causes
+problems.  An example of this is Bordeaux Threads which has a package called
+`bt`.  It's too late to change this now, but try to avoid such easily-clashing
+names when making new packages.
+
+Another question that comes up is: "I see a lot of projects called `cl-whatever`
+— should I name my projects with the `cl-` prefix?".  Some Common Lispers hate
+the `cl-` prefix and never use it.  I personally prefer this style for two
+specific cases:
+
+* A Common Lisp wrapper around something else, like `cl-cudd` (not written by
+  me), which is a set of bindings to the TODO C++ CUDD library.
+* A Common Lisp implementation of a well-known data structure or protocol like
+  `cl-digraph`.
+
+Not using the `cl-` prefix in this case would feel confusing to me, because
+you'd just be calling the project `cudd` which would be easy to confuse with the
+actual library itself.
+
+For anything that's not one of these two cases I prefer to come up with a unique
+name instead.  Sometimes it's a pun or just something that sounds unique — the
+critical part is that it doesn't conflict with anything already in Quicklisp.
+
+When you *do* use the prefix, the next question is what parts of the project get
+the prefix.  This comes down to personal preference.  Here are my personal
+rules:
+
+* The project, Mercurial/Git repository, etc have the `cl-` prefix (e.g.
+  `https://github.com/sjl/cl-digraph`).
+* The system(s) should have the same name as the project, so it also gets the
+  prefix (e.g. `cl-digraph`).
+* The packages are going to be typed frequently, and we're *firmly* in Common
+  Lisp territory at the point where we're defining packages, so it's safe to
+  drop the prefix for packages (e.g. `digraph`).
+
+Other people (including my past and future selves) might disagree on some of
+these conventions.  Feel free to take them with a large grain of salt.
+
+### Common Libraries
+
+Common Lisp doesn't have a *large* of a community as some newer languages, but
+it still has a lot of libraries because it's had a community for a longer time.
+The stability of the core language means that libraries that were written in
+portable Common Lisp ten or twenty years ago can still run just fine.
+
+In this section I'll give you a quick overview of some of the more popular
+libraries you might run into as you learn the language.  You don't have to use
+all of them, of course, but it's helpful to have some idea of what's available.
+
+#### Alexandria
+
+[Alexandria][alexandria] is one of the most popular Common Lisp libraries (the
+name is a pun on the [Library of Alexandria][library-of-alex]), and it's
+a collection of all kinds of useful little utility functions like
+`read-file-into-byte-vector` and `map-permutations`.
+
+There are a *lot* of utility libraries for Common Lisp around — one rite of
+passage is building up your own personal utility library over time — but
+Alexandria is the most popular one.  Most projects with any dependencies at all
+will eventually end up with Alexandria in the dependency graph somewhere.
+
+#### Bordeaux Threads
+
+[Bordeaux Threads][bt] was mentioned earlier.  Threads aren't part of the Common
+Lisp standard, but most implementations provide their own custom interface for
+working with them.  Bordeaux Threads wraps all these implementation-specific
+interfaces and provides an API so you can write threaded code that will work
+portably.
+
+If you're looking for something like Java's `new Thread(() -> foo()).start();`,
+this is what you want.
+
+#### CFFI
+
+[CFFI][] is a foreign-function interface library that lets you load
+C libraries (e.g. `foo.dylib` or `foo.so`) and call the functions in them.  It
+works by wrapping implementation-specific interfaces, because this isn't part of
+the Common Lisp standard.
+
+Unfortunately it has the same name as Python's FFI library, so if you're
+searching for documentation make sure you're looking at the right version.
+
+#### CL-PPCRE
+
+[CL-PPCRE][ppcre] is an implementation of Perl-compatible regular expressions.
+If you're looking to use regular expressions in Common Lisp, this is what you
+want.
+
+#### Drakma
+
+[Drakma][] is an HTTP client.  If you need to make an HTTP request, this is what
+you want.  There are other HTTP clients around, but Drakma is commonly used and
+is fine for almost anything you might need.
+
+#### Iterate
+
+[Iterate][iterate] is a replacement for the `loop` macro.  It works similarly,
+but has a more Lispy syntax and a well-defined API for extending it with new
+iteration constructs.  I personally really like it, but beware: if you get used
+to `iterate` going back to vanilla `loop` will feel painful.
+
+#### local-time
+
+[local-time][] is a library for working with time and dates in Common Lisp.  The
+standard has some basic support for times built in, but if you want to do much
+calculation with times (including timezones) this is probably what you want.  If
+you're looking for something like [Joda Time][joda-time] in Common Lisp, this is
+as close as you're going to get.
+
+[joda-time]: http://www.joda.org/joda-time/
+
+#### lparallel
+
+[lparallel][] is a library that builds on top of Bordeaux Threads to make common
+parallel processing operations much easier.  Think of it as [GNU Parallel][] for
+Lisp, with a few extra features (e.g. channels and tasks).
+
+For example: if you've got a big vector you're mapping over with
+`(map 'vector #'work some-vector)` you can split it into chunks and
+run in multiple threads by changing it to
+`(lparallel:pmap 'vector #'work some-vector)`.
+
+[GNU Parallel]: https://www.gnu.org/software/parallel/
+
+#### Named Readtables
+
+[Named readtables][named-readtables] is a library that adds namespaces for
+readtables.
+
+One painful part of the standard is that reader macros are added and removed to
+the global readtable on the fly, so if you load multiple systems that define the
+same reader macros things can get messy.  Named readtables adds some much-needed
+hygiene to that process.  If you're working with reader macros at all you
+absolutely want to use this.
+
+#### Roswell
+
+[Roswell][] is a couple of things rolled into one.  It's a C program that
+handles installing and running multiple different Common Lisp implementations
+(kind of like [NVM](https://github.com/creationix/nvm) or
+[rvm](https://rvm.io/)), and it also provides a unified way to write small shell
+scripts in Common Lisp and compile them into binaries.
+
+I used Roswell for a little over a year, but I eventually stopped and now
+I personally don't think it's worth the trouble, for a couple of reasons.
+
+First: if you write portable code you generally don't need to worry running
+a particular version of an implementation, because Common Lisp is quite stable.
+I usually just install the latest version of each implementation I use with
+a package manager or by building from source.
+
+Second: after using it for a while I found that Roswell was always quite brittle
+to upgrade, and whenever things broke it would spew an almost JVM-sized stack
+trace without a decent error message.
+
+For me, the negatives outweighed the positives.  I'd personally recommend simply
+using the latest version of the implementations you care about and writing
+portable code.  For the compiling-into-binaries functionality I'd recommend
+using your implementation's built-in support for this, or using UIOP's wrapper
+around that, or using a separate library like Shinmera's [Deploy][].
+
+Of course your mileage might vary.  If you find yourself *really* needing to run
+specific versions of specific implementations in rapid succession, you should
+look into Roswell.
+
+[Deploy]: https://shinmera.github.io/deploy/
+
+#### SERIES
+
+[SERIES][series] was almost included in Common Lisp (it's in [Appendix A of
+CLtL2][series-cltl2]), but didn't quite make it.  It's a library for writing
+functional code that looks like the traditional `map` and `filter` and `reduce`
+operations but which compiles down to efficient loops.
+
+If you're looking for Clojure's transducers in Common Lisp, this is what you
+want.
+
+[series-cltl2]: https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node347.html
+
+#### st-json
+
+JSON support in Common Lisp is a god damn mess.  There are [an absurd number of
+JSON libraries][sabra] and I don't really *like* any of them.
+
+For me, the most important quality I need in a JSON library is an unambiguous,
+one-to-one mapping of types.  For example: some libraries will deserialize JSON
+arrays as Lisp lists, and JSON `true`/`false` as `t`/`nil`.  But this means `[]` and
+`false` both deserialize to `nil`, so you can't reliably round trip anything!
+
+I've settled on using [st-json][] and wrapping it up to be a little more
+ergonomic with some glue code.  It's not the fastest solution out there, but
+it's fine for my needs.  There are plenty of other options out there, so if you
+have different needs than me you should look into them.
+
+[sabra]: https://sites.google.com/site/sabraonthehill/home/json-libraries
+[st-json]: https://marijnhaverbeke.nl/st-json/
+
+#### usocket
+
+[usocket][] is a library for sockets.  Sockets and networking aren't part of the
+Common Lisp standard, but most implementations provide a custom interface for
+working with them.  usocket wraps the implementation-specific interfaces and
+provides an API so you can write networking code portably.
+
+If you want to make Lisp listen on a port and read streams of bytes from
+clients, or want to connect to a port and send raw bytes to it, this is what you
+want.
+
+[library-of-alex]: https://en.wikipedia.org/wiki/Library_of_Alexandria
+[alexandria]: https://common-lisp.net/project/alexandria/
+[iterate]: https://common-lisp.net/project/iterate/
+[series]: https://www.cliki.net/Series
+[bt]: https://common-lisp.net/project/bordeaux-threads/
+[gray]: https://www.cliki.net/Gray%20streams
+[flexi]: https://edicl.github.io/flexi-streams/
+[ppcre]: https://edicl.github.io/cl-ppcre/
+[uiop]: https://www.cliki.net/UIOP
+[usocket]: https://common-lisp.net/project/usocket/
+[drakma]: https://edicl.github.io/drakma/
+[lparallel]: https://lparallel.org/
+[local-time]: https://common-lisp.net/project/local-time/
+[named-readtables]: https://github.com/melisgl/named-readtables
+[Roswell]: https://github.com/roswell/roswell
+
+
+## Good Luck!
+
+I hope this whirlwind tour was useful.  Common Lisp is an old, deep language.
+It's not something you can learn in a month, but if you're willing to spend the
+time it will reward careful study.
+
+Feel free to email me or pop into IRC or Discord if you have questions.  Good
+luck!