Too big a language, too small a language
Posted on 2017-09-14 Edit on GitHub
I've recently been looking into some Lisp classics, namely:
- Paradigms of Artificial Intelligence Programming (PAIP), by Peter Norvig
- The Art of the Metaobject Protocol (AMOP), by Kiczales, Rivières, and Bobrow
and, of course, Structure and Interpretation of Computer Programs (SICP) by Abelson and Sussman1.
PAIP and AMOP are about Common Lisp (CL). SICP is about building computer programs and happens to use Scheme. The contrast between the two languages is dramatic, but both are in a different ways responsible for Lisp never going "mainstream".
Though both Lisps, Common Lisp and Scheme are opposites in their design philosophies. Scheme is a small language; Scheme's R6RS standard is only 90 pages long, including indices. The CL ANSI standard is over 1,000 pages, as is the "informal" standard, Common Lisp the Language, Second Edition (Ctcl2) by Guy Steele2.
Scheme prides itself on minimalism. It's so minimal, in fact, that there are very few libraries for doing anything "practical"3. A popular joke is that Scheme is the best language–for writing Scheme interpreters. Indeed, that pedagogical use case does seem to be the reason most working programmers touch Scheme at all.
In contrast, Common Lisp prides itself on maximalism. It describes itself as an "industrial-strength" Lisp, and was intented to be the One True Lisp, a Lisp to end all Lisps4. No surprise, then, that it became an archetypal case of design by committee. Though the committee was full of brilliant people, it was also riddled with compatibility conerns, conflicting corporate interests, and big egos. As Dan Weinreb, co-founder of Symbolics and a committee member, later recalled:
We at Symbolics were forced to insist on [Common Lisp being a Lisp-2], in the face of everyone's knowing that it was not what we would have done absent compatibility constraints.
The inclusion of the loop macro, one of the committee's most controversial decisions5, was another case of one faction's interests winning out over good language design.
The result is an enormous language with over 700 functions and not one but two major DSLs (for
loop and format). Instead of creating a small core language and accompanying it with a large standard library6, Common Lisp decided to shove everything and the kitchen sink into the language itself.
If Scheme is too small, Common Lisp is much too big. The enormous number of functions, together with the extensibility of Lisp via macros, means that one person's code could be utterly incomprehensible to another. The large size is in part due to a stunning lack of orthogonality; functions like
delete-if-not shouldn't be necessary with function composition.
It's a real shame that the two defining Lisps took extreme positions along the spectrum of language design. Arc, a much-hyped new Lisp from the early 2000's that was supposed to address these issues, never picked up stream. It wouldn't be until Clojure's arrival in 2008 that the world would finally be treated to a well-designed, practical Lisp.
Which I return to again and again in a two-steps forward, one-step back fashion.
Interestingly, Cltl1 is only ~500 pages. Half the 2nd edition, it seems, was spent describing loop, CLOS, and a few other topics.
Racket, a newer dialect of Scheme, seems to have a fairly large package repository. No wonder the main site advertises the language as "batteries included".
And that it did. The ANSI standard was published in 1994, Symbolics filed for bankruptcy in 1996, and Lisp seemed doomed to be consigned to history (or at least the classroom) until Clojure came along in 2008.
loop's unlispy syntax, difficult-to-understand behavior, and lack of extensibility.
Which is how all new languages are designed today, for good reason.