Just Promise Me a Dang Spade
I’d like to learn Lisp.
I’ve dabbled in Scheme, I’ve poked at Python, but I’d really like to sit down and write a substantial piece of Lisp code [1].
Lisp seems to be the ultimate judo in algorithms, and there are no end of essays on the Web to convince you of that. Lisp practitioners almost invariably promise a life-changing epiphany for those willing to really grok Lisp.
I’m ready to believe that. I’m excited about the idea of functions as just another variable. Lisp macros sound like a whole new kind of tool. There’s a principled purity in the design of Lisp that makes my geeky heart go pitter pat. But I have one nagging doubt that I can’t shake. Before I get to it, let me qualify what I’m about to say:
- With apologies to Wittgenstein, “Whereof one cannot speak, thereof one probably ought to shut up.”
- Paul Graham is smarter than me.
So take this with a grain of salt, because I probably don’t know what I’m talking about. (Something that never stops a true blogger, right? Right! Forward ho! Fear my prow, icebergs!)
Functional languages are composed of expressions, rather than statements. An expression calculates something, and returns (or represents) a value. If it’s a pure expression, that’s all it does. A pure statement, by contrast, modifies some bit of, well, state, and doesn’t return any value.
Expressions are great, if all you ever want to do is calculate values. But not every problem is about computing a value. Functional programming gurus know this, but they act as if it isn’t true. Go off and read some essays about why Lisp is so great and you’ll see nothing but examples of mathematical functions, or sorting algorithms. The authors of those essays will practically brim over with self-satisfaction from the fact that Lisp can kick your favorite language’s butt eight ways from Sunday when it comes to writing recursive self-modifying artificially intelligent spam filter Petri nets [2]. Okay, fine, but it is not surprising to me that a language built from a sophisticated mathematical model is frickin’ great at implementing functions and algorithms. Frankly, it’d be pretty silly if it wasn’t.
A bit of advice, then, to the Lisp proponents: you’re making the wrong argument. Because, look, as a C programmer, I’m not afraid that Lisp is bad at sorting a list, or searching a tree, or recursively computing the Fibonacci sequence. I believe you when you say programs that can write parts of themselves are incredibly useful. I’m willing to learn about your magical parentheses.
What I want to know is if the things that are easy in C are still going to be easy in Lisp. What I’m actually scared of is that some PhD in a windowless room built a language that can calculate my taxes in one tiny function call, but forgot to give me an easy way to print the result to the console. Because I’ve been to grad school, and don’t try to tell me those people don’t do that kind of thing.
There’s a joke in my office that the only useful things functional languages ever do are all side-effects. “But Chris!” you say. “A side-effect is just something that happens to the state of the machine, and doesn’t affect the return value of the function! A plain old statement in C is just a Lisp expression with a side-effect and no return value!”
Fine, I understand that. But you’re missing the point, Señor Straw Man. The point is that we imperative programmers don’t like thinking of half our programs as being some dinky, unwanted side-effect. It’s a terrible term. It makes an engineer feel like a PhD is pissing on her from up in the tower where the languages are made.
I understand that Lisp allows side-effects, and I understand that the power of functional languages is in all that other stuff that isn’t side-effects. But remember, you don’t need to convince me of that other stuff. You need to convince me that I can write real live programs for real live people that draw pretty pictures on a real live screen. A computer is a state machine, and sometimes all I wanna do is change that state. Sometimes, in other words, a spade is just a spade. You don’t need it to represent a complex mathematical computation, you just need it to cut the earth.
Give me libraries. Give me lots of really, really great libraries, so I can be sure I can do what I want to do—even when it comes to side-effects like playing audio or responding to a key press or projecting a texture with OpenGL. That’s the stuff that makes me scared of Lisp, not the temporary discomfort I’d have wrapping my head around a new language model.
I look forward to my epiphany.
EDIT: I stumbled across this fascinating essay today, which provides a lucid and well written counterpoint to Paul Graham’s essay linked above. On occassion, this whole “surf the web” thing really does wash you up on a fascinating shore.
[1] – Yes, I know Scheme is really Lisp.
[2] – If you dig around long enough, you’ll find the moderate voice in the middle that champions the right tool for the job. As this fellow puts it, “If C is the closest language to modeling how computers work, Lisp is the closest to modeling how computation works.”