Racketeering — Lisp in the modern world

December 24, 2013 at 11:45 am
filed under Coding
Tagged ,

Recently I decided to give Common Lisp another shot. I like Clojure, but I want to look into Old Stuff like Lisp, and if I can add another scripting language to my toolkit, so much the better.

Except now I’m playing with Racket (Scheme). And, uh, how is it that Racket is this awesome and I hadn’t heard about it sooner? Whereas Common Lisp feels more like the product of its time, Racket feels profoundly modern, while retaining what makes Lisp special. These are of course subjective impressions from a relative Lisp neophyte. That said, I hope I’m not completely off the mark.

The last time around, I stalled out because Common Lisp didn’t seem particularly functional. I didn’t realize at the time that this is by design— Common Lisp is meant to be “powerful.” Of course depending on your perspective this can mean “disorganized,” “confusing,” or “overly complicated.” I can respect the choices but I still find them off-putting.

The LOOP macro versus higher-order functions is an example. LOOP is focused around iteration, and it’s actually a mini-language oriented around same. It leaves me cold. I’m completely sold on higher level constructs like reduce, and I’d rather write sequential operations in those terms than glorified for loops. There’s nothing wrong with for loops. But if I’m going to use FP, why bother with iteration?

Then there’s mapcar, maplist, mapcan, and lord knows what else. There are “destructive” variations on sort and such. These are all options to control how you want something done. Should I spend more time thinking how to do something rather than what to do? I prefer the opposite when programming in a higher level language. It’s why I like how map, reduce, and filter in Clojure all operate over any collection supporting the sequence abstraction.

This is actually something I think Clojure does better even than Racket but maybe I’ll talk about that another time.

Once I finished the toy CL script I’d set out to write (enumerate unique words in a body of text), I decided to check out Racket.

A huge caveat is that I’m still relatively new to all of these languages. My impressions and insight aren’t going to be particularly deep, although I’d hope they’re not completely off the mark.

That said, Racket feels incredibly polished. The website is a case in point. Common Lisp has a number of scattered resources in varying states of updated-ness. The Hyperspec is functional but with that dark gray background, it’s like it’s still 1990 at the latest. Racket has a reference and a guide, both easily searchable, and with hyperlinked references to other Racket constructs.

Threading is one area in particular which drove me a bit crazy. After playing with Go, I think it’s a significant disadvantage for any high level PL not to support CSP idioms. In practice that means channels and green/lightweight threads.

Common Lisp is barely on the map here— AIUI, threads aren’t even in the Common Lisp spec, so by default you’re left with what your implementation provides. Often this ends up looking like OS threads, which is the exact opposite if what I want to be dealing with in a higher level language.

Or you need to use some third party library, which doesn’t exactly give me confidence— there are a few implementations, one of which hasn’t been touched in years. I think most people realize by now that concurrency is hugely important and it ought to be first-class, written & maintained as a core lib.

Racket has channels and threads. Each thread effecitvely comes with its own channel, for crying out loud. There are also other constructs to assist with concurrency, like places and custodians.

If I had to describe what a dead, dying, or fringe language felt like, Common Lisp has a bunch of symptoms I would look out for. My subjective impression is that there’re N libs for a given situation. Half haven’t been touched in years if they’re even available, and the rest cover non-contiguous, sometimes-overlapping use cases.

I don’t mean to bash Common Lisp because I have a great deal of respect for it. I don’t believe that anything old in computer science/engineering is bad, and frankly I may even believe the opposite.

Lisp in particular is timeless in some sense. The particulars — car and cdr and such — often feel old, but affordances like macros, continuations, pattern matching, and tail call optimization are still novel relative to most modern programming languages.

I’m still working on my toy IRC bot implementation. It is slow going in part because I keep ratholing on learning new constructs rather than getting anything done. Yesterday I spent a bunch of time reading about Racket’s macro system, which seems to depart from Lisp’s “conventional” syntax quote, unquote, and so on. It seems like you can use that other stuff, but things like define-syntax-rule make a lot of the really basic stuff substantially easier via pattern matching, etc.

I’ll get there but what with the holidays it’s hard to find a contiguous time to spend time coding, and a new programming language requires somewhat more concentration than one I’m familiar with.

%d bloggers like this: