Let Over Lambda was published in 2008, to align with the 50th anniversary of Lisp's invention in 1958. A lot has changed since then, in both Lisp and programming practice in general. Although my thinking and opinions have evolved since, I still believe the book holds up well as a tutorial and explanation of why Lisp so special.
Anything in particular that new readers ought to know about the changes between 2008 and now?
I should revisit it again, I have the dead tree edition, and it was wonderfully quirky and informative at the time. I didn't actually use most of what I learned but loved it.
Lisp had the combination of homoiconicity and a powerful macro system, so macros are relatively easy to write and the forms they generate are easy to understand (ish).
The only macro system of equivalent power that I’m familiar with (other than other Lisps’, like Scheme) is OCaml’s p4 and it’s horrifically difficult to use (or at least was last time I looked at it).
REBOL could do things very much like Lisp macros but REBOL’s scoping story made it hard to make hygienic macros.
Prolog's goal_expansion and term_expansion mechanisms are also very interesting, as they're just Prolog rules that get executed and modify the source code. Prolog is also homoiconic. They're very easy to use. But it is not a standard feature, some Prolog systems skip it, while others implement it in subtle different ways.
not a standard feature ... implement it in subtle different ways
Understanding Lisp as a family (while this book means Common Lisp) macro systems we can different ways indeed. I've not explored expansion much, could you discuss them more or point to a nice guide? :)
You can read here: https://www.metalevel.at/prolog/macros. In Lisp I think different macro systems are different enough to not confuse them, but in Prolog on the surface all systems that implement them are similar enough to let you think they are portable. The link I shared has some issues listed but I also remember some stuff about how they interact with modules, which is also not very well defined in general...
In practice I think Prolog doesn't need the macro system as much because it isn't strictly evaluated, and we have =../2 and call/N that let us do a lot of tricks.
I also think non-strict evaluation helps reduce Haskell's need for macros, although there is a full macro system in Template Haskell that is not especially popular, although I don't have an explanation for that.
I think a lot of the original hyperbole dates to an era when the principal target of the comparison would be C and the difference between the two really is immense.
We do get such claims. From the lobste.rs front page, today:
Verus is the killer app for Rust (or something like Verus: there are a few things in this space and some of the others look potentially more promising). Rust vs C++ in systems programming has a bunch of complex tradeoffs. Rust + Verus vs C++ is not even worth a discussion, it's such a clear win on the Rust side that C++ isn't even worth considering.
[Verus is implemented in Rust using macros.]
I think something like Verus [in C++] would need some AST-level reflection
seubert | 8 hours ago
Anything in particular that new readers ought to know about the changes between 2008 and now?
hwaethere | 6 hours ago
There is an errata page and a clarifications page
ThatsInteresting | 7 hours ago
I should revisit it again, I have the dead tree edition, and it was wonderfully quirky and informative at the time. I didn't actually use most of what I learned but loved it.
Student | 8 hours ago
Why do we not get the same hyperbolic claims for macro facilities in other languages? Are other languages’ macro facilities worse in some way?
lorddimwit | 8 hours ago
Lisp had the combination of homoiconicity and a powerful macro system, so macros are relatively easy to write and the forms they generate are easy to understand (ish).
The only macro system of equivalent power that I’m familiar with (other than other Lisps’, like Scheme) is OCaml’s p4 and it’s horrifically difficult to use (or at least was last time I looked at it).
REBOL could do things very much like Lisp macros but REBOL’s scoping story made it hard to make hygienic macros.
dkl | 3 hours ago
Common Lisp also blurs the line between compile-time and run-time, which I think increases the power compared to other systems.
aarroyoc | 8 hours ago
Prolog's goal_expansion and term_expansion mechanisms are also very interesting, as they're just Prolog rules that get executed and modify the source code. Prolog is also homoiconic. They're very easy to use. But it is not a standard feature, some Prolog systems skip it, while others implement it in subtle different ways.
veqq | 4 hours ago
Understanding Lisp as a family (while this book means Common Lisp) macro systems we can different ways indeed. I've not explored expansion much, could you discuss them more or point to a nice guide? :)
aarroyoc | 2 hours ago
You can read here: https://www.metalevel.at/prolog/macros. In Lisp I think different macro systems are different enough to not confuse them, but in Prolog on the surface all systems that implement them are similar enough to let you think they are portable. The link I shared has some issues listed but I also remember some stuff about how they interact with modules, which is also not very well defined in general...
dkl | 3 hours ago
In practice I think Prolog doesn't need the macro system as much because it isn't strictly evaluated, and we have
=../2andcall/Nthat let us do a lot of tricks.I also think non-strict evaluation helps reduce Haskell's need for macros, although there is a full macro system in Template Haskell that is not especially popular, although I don't have an explanation for that.
aarroyoc | 2 hours ago
True. The SQL DSL I did for postgresql-prolog doesn't use macros and relies instead on
=../2and meta interpreters. And it's more portable.dkl | 3 hours ago
I think a lot of the original hyperbole dates to an era when the principal target of the comparison would be C and the difference between the two really is immense.
Student | 28 minutes ago
It’s true and in 2008 the main comparison would have been with c++ and Java
andersmurphy | 6 hours ago
Mostly yes, because they are often not homoiconic.
doug-moen | 24 minutes ago
We do get such claims. From the lobste.rs front page, today:
[Verus is implemented in Rust using macros.]
andersmurphy | 9 hours ago
One of the best lisp books of all time. Absolute joy to read.