On: Lisp, On Lisp, and Myself
Common Lisp, On Lisp, and me? What more could you ask for in a blog post
Happy new year!
It’s actually been a few months since I read
On Lisp,[1]
No
It’s easy to get turned off by Lisp.
The early versions of the standard are easily double my age,[2]car
and cdr
are great names,[3]terpri
and multiple-value-bind
are not.
Those last two are bad for opposite reasons, terpri
is an obscure abbreviation
and multiple-value
-bind
is verbose.
That’s an inconsequential example, but I could go on about these annoyances for dozens[4]
- using
thingp
(and sometimesthing-p
!) forp
redicates instead of the clearly superiorthing?
- the pathname situation that the venerable Practical Common Lisp[5]
- I actually read PCL a year or so before On Lisp. ↩︎
deemed dire enough to dedicate a whole chapter to redesigning.[6]- It’s a good chapter, don’t get me wrong. ↩︎
- and the case-insensitive reader and
UPPERCASE
standard symbols, which are far more inconvenient than any case errors.
That last nit is particularly exasperating because Doug Hoyte insists on venerating it as a feature
in his otherwise compelling and elucidating Let Over Lambda.[7]
Minor issues like these kept me from sticking with Lisp for any substantial amount of time, and made Schemes look all the more appealing.[8] Racket is more accurately described an infinite set of interoperable Racket dialects. It’s complicated, and interesting, but By the way, I’m still (somewhat) active in the official Racket discord guild. It’s a great group! ↩︎racket/base
is my go-to.
But, you know what? All of this doesn’t matter. It matters a little bit, but it doesn’t matter!
Yes
To be honest, I skimmed the full programs in On Lisp; what grabbed me were the utilities.
Here’s the magical thing: Lisp lets you solve any[10](optimize (speed 3) (safety 0))
and define-compiler-macro
(another inconsistent name!),
but SBCL is a dang hard compiler to beat in the dynamic space. ↩︎
Example
If I had to pick a single example that best convinced me that Lisp was for me,[12]
Take this Scheme code:
(define (∘ f g) (lambda (x) (f (g x))))
and compare it to this Lisp code:
(defun ∘ (f g) (lambda (x) (funcall f (funcall g x))))
No contest, right? Even if you don’t care much, this is the kind of stuff that gets to me!
But what if I just…
(defmacro fpromote ((&rest fs) &body body) `(flet ,(loop for f in fs for args = (gensym "args") collecting `(,f (&rest ,args) (apply ,f ,args))) ,@body))
and then…
(defun ∘ (f g) (fpromote (f g) (lambda (x) (f (g x)))))
See?
For the longest time, the separate function and value namespaces in Lisp turned me off, and with five lines of code, I eliminated the problem in many cases that I encounter—I
use fpromote
almost twenty times in my utils.lisp
!
Myself
There’s an essay that has been submitted almost two dozen times to Hacker News titled
The Bipolar Lisp Programmer.[13]
Advice
Here’s five[14]
I’m not sure there’s any value in trying to convince people how great your favorite programming language is. xkcd 386 is my desktop wallpaper for a reason.
I was originally intending to have no Lisp code, there’s plenty of Lisp evangelism out on the web, but I couldn’t resist making one attempt.
- Experimenting with programming languages is so fun. Do it as much as you want to!
However, use the programming language you like the most all the time.
In the hands of someone experienced with solving their own problems, even a language like
C++
can become an exceptionally useful tool that is a joy to use. - Publishing should be your default. In my experience, it is fascinating to look back at my old code, and it is incredibly fun to discuss your code with others—if
fun isn’t enough to motivate you,[15]
- Laaaaaaaame!!!!!!!! ↩︎
remember that you’ll realize many things you could have done better… as soon as other people can see your code :P. Also, most software forges let you “publish” things privately, so you can hedge your bets. I’m always bummed when I don’t have access to my old code. Linked lists suck, but use whatever is most convenient for your first draft. The adage goes that “nothing is more permanent than a temporary solution,” but, especially for code you write for you, consider this alternative adage: “if it’s stupid and it works, it’s not stupid.”
“[A]bout 97% of the time: premature optimization is the root of all evil.”
― Donald Knuth
- Finally, learn from your mistakes, but wallow not: push forward and do what makes you proud.[16]
- It’s easy for me to agonize over past wasted time, which wastes more time. The second best time is always now! ↩︎