Lisp - facts and myths
======================
tl;dr - Lisp's reputation as an elegant, austere and mathematically
beautiful language is misleading at best. In reality, Lisp is a
crocky but powerful old language that has carved out a home in
academia and stubbornly refuses to die. It is more a Unix or Perl
than a lambda calculus or a Turing machine.
- Myth: Lisp's magic comes from first-class functions and lexical
closures.
- Fact: Common Lisp separates the function namespace from the variable
namespace, so from some perspectives it does not have first-class
functions. Scheme, and Python, uses the same namespace for
variables and functions. In the Lisp world this is called being a
"Lisp-1" as opposed to a "Lisp-2". Python uses its unified
namespace to implement function decorators as higher-order
functions, which permits some neat tricks such as [memoizing
recursive functions after they are defined]. This technique also
works straightforwardly in Scheme, but less straightforwardly in
Common Lisp. So there's an example of how CL is less a functional
language than Python! As for lexically scoped closures, Python has
those too -- admittedly Python's scoping is a bit lax but it's
possible to put together let-over-lambdas the same way you would in
Lisp. They just don't look exactly like they would in Lisp.
- Myth: Lisp's magic comes from macros.
- Fact: Macros are fundamental to the language, but there isn't one
particular macro system that has the magic. Different Lisps do
macros quite differently. The first macro-like feature was fexpr,
which appeared in the 1960s and has fallen out of use. Nowadays,
Common Lisp has defmacro, and Scheme has syntax-rules and
syntax-case. Some Lisps have a one-off macro system that no one
else shares, such as Chicken Scheme's implicit renaming or Clojure's
hygienic version of defmacro. So the lesson Lisp teaches about
macros is "Have macros", and the rest is [a work in progress].
- Myth: Lisp's magic comes from conditions and restarts. Instead of
crashing you can live patch your code and continue.
- Fact: This feature is not broadly available across the Lisp family.
Only Common Lisp has restarts. Emacs Lisp does not have restarts.
Scheme does not have restarts. Further, it is up to your Common
Lisp implementation to decide what restarts it is going to provide
in the REPL. SBCL has a lot of good ones but smaller compilers like
ECL do not. So this is an area where SBCL has magic but "Lisp" does
not.
- Myth: Lisp's magic comes from being a small, elegant, mathematically
pure language.
- Fact: People who make this claim usually cite McCarthy's [LISP 1.5
Programmer's Manual] that draws parallels between Lisp and lambda
calculus. Or, they cite Alan Kay who called Lisp the "Maxwell's
Equations of Software". It's true that a Lisp can be built from
eight primitives, CAR CDR CONS EQ ATOM COND QUOTE LAMBDA, but no one
does that [except for fun]. First, the resulting language would be
pure-functional, as none of the primitives are capable of
side-effects: real Lisps are not pure-functional. Second, the
resulting language would not be [runtime-metaprogrammable]: you
would need to implement a nested interpreter if you wanted macros or
even fexprs. Finally, defining the core primitives doesn't specify
the behavior of the interpreter that's executing them, so important
behaviors like scoping and order of application [aren't defined].
Real minimal Lisps are built from Scheme's core primitives, which is
still a pleasingly small list of stuff, but less small, and
considerably less mathematically pure and harder to implement than
the above.
- Myth: Lisp's magic comes from being carefully and thoughtfully
designed by smart people.
- Fact: Lisp has committed many blunders. Examples: It used dynamic
scope until the 1970s, by which time ALGOL and even C had lexical
scope. The Common Lisp and Scheme standardization efforts have both
suffered from legendary politics, schisms, and at least one
standardized bug (Scheme R6RS records; see [SRFI-99] for
background). In other words, Lisp evolved organically and made lots
of mistakes, just like any other language.
- Myth: There is no point in using Lisp.
- Fact: If you need a Lisp-only feature or are planning to extend the
language yourself, use Lisp. If not, use Python instead.
[memoizing recursive functions after they are defined]
[a work in progress]
[LISP 1.5 Programmer's Manual]
[except for fun]
[runtime-metaprogrammable]
[aren't defined]
[SRFI-99]