61af4332b802

More todos
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Wed, 15 Aug 2018 04:50:36 +0000
parents bf23f95dcb71
children 5882653249ed
branches/tags (none)
files content/blog/2018/08/a-road-to-common-lisp.markdown

Changes

--- a/content/blog/2018/08/a-road-to-common-lisp.markdown	Mon Aug 13 06:36:09 2018 +0000
+++ b/content/blog/2018/08/a-road-to-common-lisp.markdown	Wed Aug 15 04:50:36 2018 +0000
@@ -1,7 +1,7 @@
 +++
 title = "A Road to Common Lisp"
 snip = "One way to learn this old language."
-date = 2018-08-01T16:00:00Z
+date = 2018-08-15T16:00:00Z
 draft = false
 
 +++
@@ -492,8 +492,6 @@
 
 ### Lisp as a System
 
-TODO gabriel paper
-
 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.
@@ -570,7 +568,7 @@
 breathing programming [*system*][gabriel-system] goes beyond just the short
 feedback loop and interactive REPL, too. 
 
-[gabriel-system]: 
+[gabriel-system]: https://www.dreamsongs.com/Files/Incommensurability.pdf
 
 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
@@ -609,11 +607,13 @@
 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][mickens TODO] on
+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!
 
+[blood stains]: https://www.usenix.org/system/files/1311_05-08_mickens.pdf
+
 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.
@@ -636,8 +636,13 @@
 news is that you're going to need to shave the editor yak.  You really only have
 two choices here:
 
-* Emacs with [SLIME][TODO] or [Sly][TODO].
-* Vim (or Neovim) with [Vlime][TODO] or [Slimv][TODO].
+* Emacs with [SLIME][] or [Sly][].
+* Vim (or Neovim) with [Vlime][] or [Slimv][].
+
+[SLIME]: https://common-lisp.net/project/slime/
+[Sly]: https://github.com/joaotavora/sly
+[Vlime]: https://github.com/l04m33/vlime
+[Slimv]: https://github.com/kovisoft/slimv
 
 I wish this weren't the case, but those are really only the realistic options
 today (aside from the editing environments for the (expensive) commercial
@@ -654,17 +659,19 @@
 choice.  This will be a lot of fiddly metawork, but will pay off handsomely as
 you continue working in Lisp.
 
-On a side note: if anyone is interested in making a Common Lisp [LSP][TODO]
+On a side note: if anyone is interested in making a Common Lisp [LSP][]
 language server, I think it would be a hugely useful contribution to the
 community.  Having an LSP server would mean you could get a much nicer
 programming experience in many editors out of the box, which would help new
 people quite a lot.  I think you could piggyback on top of Swank to do a lot of
-the language-side stuff, and it would mostly be a matter of implementing the LSP
-interface.  If this sounds interesting to you, please let me know — I'd be
+the language-side stuff, and it would mostly be a matter of implementing the
+LSP interface.  If this sounds interesting to you, please let me know — I'd be
 willing to help.  I've done a bit of work at my day job making a Scala LSP
-language server that uses IntelliJ as a backend, so I have at least some idea of
-how that sausage gets made.  I just don't have the time or motivation to do an
-entire LSP server for Common Lisp all by myself.
+language server that uses IntelliJ as a backend, so I have at least some idea
+of how that sausage gets made.  I just don't have the time or motivation to do
+an entire LSP server for Common Lisp all by myself.
+
+[LSP]: https://langserver.org/
 
 ### Learning Paradigms
 
@@ -674,15 +681,17 @@
 practice using your fancy new environment.
 
 I think the perfect book for both of these is [Paradigms of Artificial
-Intelligence Programming][TODO], often abbreviated as PAIP.  The book was
+Intelligence Programming][PAIP], often abbreviated as PAIP.  The book was
 recently made available for free as a PDF, or you can buy a paper copy from
 if you prefer.
 
-This book was written in 199 TODO so it's not about the hyped up AI fields
-you've been hearing about in the news like machine learning or deep learning
-— instead it's a tour of [Good Old-Fashioned AI][gofai].  Even if you're not
-particularly interested in this kind of AI, the book is a great example of how
-to write Common Lisp code.
+[PAIP]: https://github.com/norvig/paip-lisp
+
+This book was written in 1992 so it's not about the hyped up AI fields you've
+been hearing about in the news like machine learning or deep learning — instead
+it's a tour of [Good Old-Fashioned AI][gofai].  Even if you're not particularly
+interested in this kind of AI, the book is a great example of how to write
+Common Lisp code.
 
 One thing I really love about this book is that almost all the functions in it
 have docstrings.  If you look at most other programming books they omit the
@@ -705,14 +714,14 @@
 — really digging into a problem is exactly what you need at this point in your
 Lisp journey.
 
-[gofai]: TODO
+[gofai]: https://en.wikipedia.org/wiki/Symbolic_artificial_intelligence
 
 ### Recipes for Success
 
 The final technical book I'll recommend to every aspiring Lisp programmer is
-[Common Lisp Recipes][recipes-TODO], sometimes abbreviated as CLR.  Unlike most
-of the other books I've recommended so far this one is relatively recent: it was
-published in 2015 TODO.  It's not free, but I think it's well worth the money it
+[Common Lisp Recipes][recipes], sometimes abbreviated as CLR.  Unlike most of
+the other books I've recommended so far this one is relatively recent: it was
+published in 2015.  It's not free, but I think it's well worth the money it
 costs.
 
 The book is written by the author of several very heavily used Common Lisp
@@ -721,6 +730,8 @@
 well-written grab bag that will teach you a lot of things you won't find in
 other books.
 
+[recipes]: http://weitz.de/cl-recipes/
+
 ### Final Patterns
 
 If you've gotten this far you're pretty invested in Common Lisp, and I want to
@@ -896,9 +907,9 @@
 
 #### Packages
 
-We often see questions in `#clschool` 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*.
+We often see questions in IRC and Discord 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
@@ -926,20 +937,24 @@
 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.
+This gives you the flexibility to work however you want.  For example: in my
+procedural art library [Flax][] most of the packages are each used in one
+specific file, much like you would do in modern languages.  But the
+`flax.drawing` package contains not only a drawing protocol but also several
+implementations of it (PNG, SVG, etc), and so I split the code into [a series
+of separate files][flax-drawing], each one dealing with how to draw a single
+format (plus one for the protocol itself).
+
+I could have created separate packages for each implementation and set up the
+imports/exports between them, but I didn't feel like the extra boilerplate was
+worth it.  Common Lisp is flexible enough to let you make such choices.
 
 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
+[symbols]: http://stevelosh.com/blog/2016/06/symbolic-computation/
+[Flax]: https://github.com/sjl/flax
+[flax-drawing]: https://github.com/sjl/flax/tree/master/src/drawing
 
 #### Systems
 
@@ -952,15 +967,19 @@
 * 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.  And since Common Lisp
-gives you the power to abstract almost anything, people eventually abstracted
-the process of loading Common Lisp code.
+[section 11.9][cltl2-packages] of CLtL2 you'll see that it was imagined that
+each author would write their own custom file to load their code.  But since
+Common Lisp gives you the power to abstract almost anything, people eventually
+abstracted the process of loading Common Lisp code.
+
+[cltl2-packages]: https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node120.html
 
-[ASDF][TODO] 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][] is a Common Lisp library bundled with most 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]: https://common-lisp.net/project/asdf/
 
 ASDF standardizes the process of defining a system into something like this:
 
@@ -971,10 +990,12 @@
 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.
+The [ASDF manual][] 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.
+
+[ASDF manual]: https://common-lisp.net/project/asdf/#documentation
 
 Systems and packages are orthogonal in Common Lisp.  Some systems (like small
 libraries) will define exactly one package.  Some systems will define multiple
@@ -984,8 +1005,10 @@
 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.
-* One of the files specified for loading is [`packages.lisp`][cl-digraph-packages], which creates a package called `digraph`.
+* That system has a description of how to load the code, which lives in the
+  [`cl-digraph.asd`][cl-digraph-asd] file.
+* One of the files specified for loading is [`package.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
@@ -997,7 +1020,7 @@
 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 `packages.lisp` file which contains all the definitions for all the
+* 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
@@ -1009,9 +1032,9 @@
 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
+[cl-digraph]: https://github.com/sjl/cl-digraph
+[cl-digraph-asd]: https://github.com/sjl/cl-digraph/blob/master/cl-digraph.asd
+[cl-digraph-packages]: https://github.com/sjl/cl-digraph/blob/master/package.lisp
 
 #### Projects
 
@@ -1019,30 +1042,30 @@
 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:
+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 string-wrapping library [Bobbin][] is
+a project that defines *two* systems:
 
-The `cl-digraph` system contains the actual data structure and API.  It has no
+[Bobbin]: https://github.com/sjl/bobbin
+
+The `bobbin` 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`
+The `bobbin/test` system contains the unit tests.  It depends on the
+`bobbin` 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.
+[Graphviz]: https://www.graphviz.org/
 
-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.
+Both of these systems are defined in the [`bobbin.asd` file][bobbin-asd].  ASDF
+[treats systems with a forward slash in their name specially][asdf-slash] and
+knows to look for them in the `asd` file named with the text before the slash.
+
+[bobbin-asd]: https://github.com/sjl/bobbin/blob/master/bobbin.asd
+[asdf-slash]: https://common-lisp.net/project/asdf/asdf.html#index-find_002dsystem
 
 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
@@ -1051,14 +1074,17 @@
 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, which is why you need to install it separately.
+[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
+:bobbin)` you’re asking Quicklisp to download Bobbin (and any dependencies) if
+necessary, and then hand it off to ASDF to actually load the code of the
+`bobbin` 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, which is why you need to install it
+separately.
+
+[Quicklisp]: https://www.quicklisp.org/beta/
 
 #### Recap