POSTS

Quitting the Land of Lisp

Blog

Despite its creative approach and genuinely delightful music video, “Land of Lisp” by Conrad Barski, MD presents significant challenges for learners.

The remainder of this post isn’t one of those “I failed but then persevered” stories. Instead it is about how even a supposedly beginner-friendly book with cute comics and clever humor can make you feel like an impostor in your own profession – even 25 years in. It’s about finding, despite living your life on a lode of stubbornness, the courage to close the tabs, delete the ebook from your iPad, and move on. For those that don’t read the body, I’d recommend David Touretzky’s Common Lisp: A Gentle Introduction.

This post is also a look at how I approach authoring curriculum in my work: what I offer my learners and what offends my sensibilities. If you’re into writing technical curriculum, this might be an interesting exploration. Code samples and quotes will be given. This will be a longer post.

My principal complaints about Land of Lisp are these:

  1. The code samples leap around in difficulty in a way that hampers learning and which invites imposter syndrome. Instead of what I or a median learner needed, the book served the author’s interests in a way that suggested I was beneath the book, or it was embarrassed by writing to my level of need
  2. The book’s structure and over-packed code listings assume dedicated blocks of focused time that most working professionals – and especially parents – simply don’t have.1
  3. As a variant of #1, above, the book’s tasks also consistently bring in extraneous tools and concerns (Graphviz and directed graph syntax) at the expense of covering tools and concerns that are a core part of Lisp practice and culture (e.g. Lisp’s unique interrupts, its formidable debugger, the SLIME/SLIMV environments)

But its video is a stone-cold bop. 2

The Call to Adventure

In 2024, I set out to climb one of programming’s most mystical mountains: learning Lisp. Prompted by Eric S. Raymond’s inspiring yet gnomic words

Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot.

I bought a new notebook, checked my pens’ ink levels, and sat with focus and attention.

The Adventure Ends

According to my git log, I made it until exactly Tue Jul 23 17:19:01 2024 -0400 on a quest that had seen small steps of progress for 7 months.

I had slowed down to a crawl during “Grand Theft Wumpus (p. 140, Chapter 8, ~33% complete) thanks to a bunch of side quests: learn to use advanced debugging tools to figure out what’s wrong; use the (describe) form to extract data; use the (trace) form to get backtraces.” I left “…Wumpus” figuring that I’d made the investment and that the rest of the book would be a breeze. This was wrong.

The subsequent game, “Orc Battle (p. 173; ~40% complete)” was a similar slog. I’ll confess, I didn’t code it up. I was tired of this book, its writing style, its pedagogical approach, and its lack of empathy for its reader.

Rather irked, when I saw yet another slog shaping up in “Evolution (p. 200; ~40% complete),” I just gave up. I didn’t dramatically abandon the project. I just…stopped opening that particular tmux session.

Ego

As I kept avoiding returning to the book and its exercises, the self-doubt crept in:

Dammit, I’m not someone who quits hard things! I ground through to the great reward of Margaret Atwood’s The Blind Assassin3 ; I atomized ‘Infinite Jest’; I learned Latin, Dutch, and French; I am a parent – of a toddler!

On top of that, if you visit the Amazon page for the book, you will see technologists of note endorsing the book.

Oh Steven, online programming luminaries agree, this book is great,  and you are too dumb to enjoy it.

Oh Steven, online programming luminaries agree, this book is great, and you are too dumb to enjoy it.

But the Reddit forums suggest that I’m not the only one struggling with the book.

After a decade of being a technical educator, I have earned the standing to say this: sometimes the problem isn’t the learner, it’s the material. To the benefit of future technical book authors/editors here’s why this book fails for me as a learner.4

Is Land of Lisp Embarrassed to Write Beginner-Grade Code?

Land of Lisp starts tipping its hand about its incorrectly-calibrated tone early.

Accidental Complexity I

As of page 26 we are going to play a guessing game. The computer is asked to guess a number in a range; it divides the range in half and guesses a number between low and high; the programmer provides the feedback of lower or higher (thus halving the range); the program then bisects between the guess up to the top end or from the guess to the bottom end; repeat until found. This is a light-hearted demonstration that models a powerful search technique: binary search.

The crucial step here is finding the halfway point between two numbers. How to code this?

  • Option 1: Use simple division (x / 2) and stipulate that “x is even”
  • Option 2: Hand-wave around integer division (x // 2) and explain that this drops remainders when x is odd

Land of Lisp’s choice? Casually toss in a function that does a bitwise right-shift on x’s base-two representation.

Rude.

So in order to explore the book’s most basic challenge, you have to digress into:

  1. Integer division versus decimal (“floating point”) division
  2. Binary representation of decimal numbers
  3. Bitwise shift
  4. The New Math-style proposition that a right shift of one position halves the binary representation of a number without remainder
  5. 2, above, but in reverse

And, in this, we see in microcosm everything that will go wrong and continue to go wrong in Land of Lisp. This problem reappears so many times I can only blame the editors for not taking Dr. Barski aside.

Accidental Complexity II

While chapters 3 and 4 proceed more or less like an introductory Lisp book and are rather enjoyable. Chapter 5 has you build a basic (3-location) “dungeon traversal” e.g. Zork game. But it’s here, again, that some yellow flags start flying as some extraneous changes make the reader ask “Why?!” in a way that’s not addressed or explained. Let’s look at a few code samples.

The rooms in the dungeon are listed as:

(defparameter *nodes* '((living-room (you are in the living-room.
                                      a wizard is snoring loudly on the couch.))
                        (garden (you are in a beautiful garden. there is a well in front of you.))
                        (attic (you are in the attic.
                                there is a giant welding torch in the corner.))))

OK so that’s the rooms. And they’re connected via edges:

(defparameter *edges* '((living-room (garden west door) (attic upstairs ladder))
                        (garden (living-room east door))
                        (attic (living-room downstairs ladder))))

And now we’re going to populate those rooms with inventory. Both the listings to this point go roomcontent. So surely have *object-locations* points to a list where the key is room-name, right? That’s principle of least surprise, no? Guess what Land of Lisp does.

(defparameter *object-locations* '((whiskey living-room)
                                   (bucket living-room)
                                   (chain garden)
                                   (frog garden)))

Groan.

Yep, it inverts the patterns. Surely there’s a good reason? If so, the book doesn’t provide it. Sometimes educational materials make a switch like this in order to highlight a language features or to model that sometimes we work with non-ideal data forms. But there’s no motivating discussion in the book.

Again, I fault the editing here. Any beginner/intermediate learner would have bubbled this inconsistency and a technical editor certainly should have had enough empathy to detect it. It’s as if Barski has been using Oxford comma series for multiple chapters and then decided to stop. Or colour started appearing instead of color in even-numbered chapters. It’s weird like the Berenstein Bears paradox.

Chapters after 5 return to and maintain a pretty solid footing in the basics of Lisp. Chapter 6 sees us building a custom Read-Evaluate-Print-Loop (which is a super-awesome power of Lisp) and Chapter 6.5 has a deep dive into lambda, a powerful idea that many other languages have stolen been inspired by.

Chapter 7 brings forth another variant on Accidental Complexity: It’s Tooling Complexity.

Extraneous Tooling

OK, here is a progression of concepts in Chapter 7:

  1. List links (aka cons) being links links in a chain
  2. Improper lists (aka cons that doesn’t terminate in nil)
  3. Pairs (cons lists as dotted pairs as in a Cartesian (x, y) notation or points)
  4. Circular lists (a link that points back to a member of its chain)
  5. Association lists
  6. Tree structures
  7. Installing Graphviz
  8. Generating Graphviz input files
  9. Labeling nodes in Graphviz files
  10. Building programs to generate Graphviz files
  11. Injecting behavior called “thunks” to create flexibility in…sigh…Graphviz files
  12. Writing directed graph files for Graphviz

OK, I think that should be enough. When the list items get italicized, that’s when the focus moves from “using Lisp to represent Lisp data structures” to “using Graphviz to (many, many pages later) draw the same thing.

My question is this: whom did this additional complexity serve? Lisp and Lisp instruction has existed since the early 60’s without graph drawing toolkits being readily available. Why this tool? Why now?

If the example is so complex that you need a sophisticated toolkit, you’re not writing a book for beginners. If you’re writing for beginners, then your examples need to be small in which case you don’t need a sophisticated graph-drawing program.

Let’s suppose that you’re on an old computer or it’s a computer that you’re uncomfortable installing software on. Congrats, this requirement just tanked Lisp for the sake of drawing circles and arrows. And in my years, I’ve met some very talented and/or educated programmers who have had no sense of systems administration, even with tools as easy as apt or brew.

Now, one might think: “Well, just skip it; If you don’t care, maybe you don’t need it. Don’t let it hang you up.” But that is impossible since Graphviz representation is required in chapter 8’s project. And this is also an error when writing curriculum. Later modules’ completion should not be contingent on a certain level of achievement in an earlier module without providing multiple failure recovery modes.

Given the foregoing discussion, you might guess that this is a warning sign that Land of Lisp doesn’t really care to test whether the example is too complex. You would be right – as we shall soon see.

Intermission: Useful Tooling

As a counter-example to Graphviz, what if Barski had done a deep dive (as is probably appropriate at the ⅓ or ½ mark) to look at Lisp’s powerful debugger system or interrupts system? That would have been finegreat even. Heck, entirely appropriate and a nice way to break up the curriculum.

Lisp has an interesting design approach that when it crashes, it doesn’t blue-screen like a Windows PC; rather, it stops right before it detonated and asks the programmer to introduce some new code or to manually make a decision to help the program get running again.

Example of an interrupt caused by division-by-zero error

Example of an interrupt caused by division-by-zero error

This system is called interrupts and it’s amazing. In fact, NASA launched satellites running Lisp and engineers on Earth were able to debug and fix the satellite in interplanetary space when space’s cruelty made certain memory sectors fail. Amazing! And it’s present in every Lisp environment! Amazing! Know what’s not really amazing? Drawing graphs! Didn’t care, didn’t want.

Or, and this is also a profound show of non-empathy for the user, Land of Lisp writes as if you’re typing in hundreds of lines of code to run the program that Barski is demonstrating. No! Lispers only do this for very small amounts of code or when they have very high expertise (few mistakes). Most Lisp developers start a Lisp “session” and use their code editor to push new lines of code into it. Yes, it’s really just a fancy copy-and-paste, but it is what Lisp developers actually do – every day! I wouldn’t have minded a tangent covering SLIME/SLIMV that would have saved my aching fingers.

Or, why not show off Lisp’s debugging functions or debugger with breakpoints? As my old colleague Sherif said: “Most of the time programs are not working. Why not put debugging and writing broken code first, not last?” Sage man. Why most programming languages don’t put their debugger front-and-center baffles me.

Section Conclusion

At this point, I think you’ve seen that the book has fundamental flaws:

  1. An absentee editor failed to reel Barski in
  2. Examples that needlessly add in complexity in material
  3. Examples that needlessly add in complexity in development tooling
  4. Examples that build materially on each other and thus promulgate/magnify failures
  5. Examples that, in aggregate, communicate “I’m bored of you” to the reader

But everything to this point was prologue. Chapter 8, “Grand Theft Wumpus” made me ask: “Does Land of Lisp hate me?”

Does Land of Lisp Hate Beginners?

First, let’s just say it, taking cues from early 00’s hyper-violent video game series “Grand Theft Auto” and uniting it with venerable programming introduction “Hunt the Wumpus” is hilarious and funny and awesome. Again, Barski seems funny, and smart, and like a hell of a musician. Oh and he drew the mascot Lisp alien featured in the book and now in the larger Lisp programming community. Honestly, I’d like to meet him.

Can’t break that which is running away in 3…2…1

Can’t break that which is running away in 3…2…1

But like Ivan Drago in Rocky IV, Chapter 8 was out to break me. But I decided I would out-stubborn it. To be fair, it necessitated a series of side quests that required me to read blogs, search the internet, and shave yaks in order to figure out what the code samples were doing. And I was better at the end. But it wasn’t an engineered experience.

Chapter 8 (“Wumpus”) is Not Digestible

I have to credit Land of Lisp for teaching me, as a curriculum author, a new rule: always make progress possible in the duration of a baby’s nap. Phrased differently, never assume dedicated blocks of focused time new parents (and also most working professionals) don’t have.

Dig this:

There are people who are dying for a chance to try out your technical thing.

You should be honored. Facing the prospect of dragging their exhaustion a tad farther late at night, early in the morning, or during a baby’s nap, they’re trading time with your thing over legions of other opportunity costs.

In the hours they couldn’t get time in front of a device, they dreamed of your thing and what they would do or learn when they got there.

They finally get their duties addressed and are excited to get that dopamine payoff of learning…you then throw them Graphviz installation drama, or over-complex examples, or non-repeatable examples (ahead), or examples that don’t work through/demonstrate intermediary state (ahead) or that use advanced formulations for doing the same work. And before they get one step closer to solving the problem you’ve laid out for them, the baby wakes up, their time with you is over and they’re back on the clock.

Chapter 8’s methodology all but ensures one will never get the thrill of “I learned a thing” during a baby’s nap. Land of Lisp had led us through a cozy wizard’s house in Chapter 3. Now it throws us into a house filled with concertina wire, like something out of Suspiria.

OK, in fairness, it never is this bad

OK, in fairness, it never is this bad

Let’s describe how the chapter’s construction fails readers’ sense of progress.

Its Setup Is Random, and Thus Non-Deterministic

In a real game, randomness is an essential factor: dice, spinners, bones. But I’m not reading a book on game design, I’m trying to learn a programming language and so making the world constant so that I can reply my steps over, and over, and over again until I understand how things hang together is crucial to programming learning.

Chapter 8, sigh of course, makes its first functions randomizing the game board. We could have been given a hard-coded game board (A quick download!) and add randomization later once the game’s play mechanics were clear. But no, that’s not how Land of Lisp rolls (get it?). Every game play will be necessarily different. Good luck debugging that in a language that you’re, admittedly, new to! It’s like being asked to patch a hole in an inner tube that randomly moves. Rude.

It Infers Intermediary States Are Clear When They Are Not

The first code listing with action in it is this:

(defun random-node ()
  (1+ (random *node-num*)))

(defun edge-pair (a b) (unless (eql a b)
                        (list (cons a b) (cons b a))))
                        
(defun make-edge-list ()
 (apply #'append (loop repeat *edge-num*
                  collect (edge-pair (random-node) (random-node)))))

At this point I was thinking, “Not so bad.” I think this will make big list of a->b and b->a pairs. Basically, that’s the work of (edge-pair) and then aggregating them all is the work of (make-edge-list). Even knowing 30 minutes of Lisp, you might be able to squint and guess how the language indicates those ideas that I summarized.

But you can test this hypothesis a few paragraphs later where Land of Lisp gives you a listing of the results and, indeed, it looks like:

((16 . 20) (20 . 16) (9 . 3) (3 . 9)....

Hey, cool, I got it. Yay! I made a good step before the baby woke up. Let’s try to do the next section…oh…my….

Well, thanks for teaching me to walk and now laughing and pointing when I can’t ice dance backward in the dark with a blindfold on

Well, thanks for teaching me to walk and now laughing and pointing when I can’t ice dance backward in the dark with a blindfold on

This is not nice. Where is the editor? We just left a mellow chapter on (lambda) and directed graph drawing program: what’s this?! It’s like a cut-and-paste error (it’s why I blame an editor versus Barski). There’s no ramp up to this listing. Either I’ve been an idiot this whole time and this listing proves it, or there’s a discontinuous leap in expectation here.

Like I said, I got through this chapter (barely). So, in order to figure this out, I learned to use the debugger and interrupts systems mentioned previously to inspect the various intermediary states that this code summons.

Very few of those steps could be accomplished in a baby’s nap. This listing took me several days. Sure, if I were 22 and could sit in a library all day interrupted by lunch and vape breaks, I would have moved faster, but this is a chauvinistic and ignorant and cruel assumption.

Authors can forget their audience when they’re surrounded by experts day-in and day-out, but the editors completely burned all their credibility with me in these 3 pages.

Conclusion

That’s enough. Shortly after this slog, I saw another slog in the next chapter and a slog after that one. It drove me away until – months later – I just to admit that I was going to abandon Land of Lisp.

I learned a lot about writing curriculum via anti-example and I did learn a bit about Lisp, but I could have covered that same content more effectively, more efficiently, by using Touretzky’s book…which while it does not teach Graphviz quite as well does manage to deliver on the core concepts and some of the most powerful debugging tools clearly and concisely.

Footnotes

  1. Those without wives or moms or a horde of wealth to buy servants to scaffold them an existence will find it hard to give this book the requisite amount of focus and short-term memory required to progress through it. The level of focus to exclusion of all other responsibilities suggest someone who was a 14th-century Calabrian monk, or who endured medical school and residency – ooohhhh….
  2. Seriously, and I mean this with full earnestness, what a kick-ass music video! Lauren and I will spontaneously sing it or reference it around the house nearly a half-decade after first seeing it. It’s like Camper van Beethoven met a Lisp AI researcher from 1988, and they made this video in their funky Minnesota garage over a few brews. I guess if medicine or programming don’t work out for Barski, he has a backup career in penning jingles. 🤣
  3. I may credit this book for my stubbornness in never giving up on movies or books – even technical ones. I was cool on the book for 85% of its duration and then, in the last 15%, the reveals unwound and I realized I had read the work of a genius.
  4. This phrase comes from David Foster Wallace whose magnum opus, Infinite Jest, ends without a clear concluding note. Said Wallace: “….there is an ending as far as I’m concerned. Certain kind of parallel lines are supposed to start converging in such a way that an ’end’ can be projected by the reader somewhere beyond the right frame. If no such convergence or projection occurred to you, then the book’s failed for you.”