Sunday, January 2, 2011

More fully-featured, modern Lisps, pulleezz


``Horsey Horseless''

While I don't like the tone of my earlier post, No more "minimal early Lisps", pulleezz, I stand by its core message: implementing a "minimal early Lisp" may actually be bad for you.

Why? An analogy: if you want to learn how to build a car, learning to build a horse carriage doesn't seem right. And the difference between "LISP" and modern Lisps is similar to that between horse carriages and cars.

IMO, modern "mainstream" Lisp (Common Lisp, Scheme, Dylan, Goo, EuLisp, ISLISP) is the king of dynamic languages. All the others (PHP, Lua, Python, Ruby, ...) are merely variations on the theme.

Compared to Haskell, Lisp is a big hack. But it has its uses. And over the course of decades, Lispers have accumulated a wealth of tricks to cope with the hackish character inherent in Lisp.

So if you reimplement an early Lisp, you're missing out on a lot of stuff, just like Lisp's "successors" in the dynamic language area do. It's a shame, really. IMO, if you care about Lisp, you owe it to yourself to not only learn about "LISP", but also what happened in the 5 decades since.

And I also think you owe it to others. The world is already plagued enough by bad programming languages. If you want to put out a new one, even if it's meant just as a toy, by all means do us all a favor and study history first.

Here's a list of some of the stuff that I think every Lisp (re-)implementer should care about:

Bindings


Understand the difference between SETQ and DEFPARAMETER for global variables.

Understand PROGV and BOUNDP. Ponder their absence in Scheme.

Understand Scheme's LET, LET*, LETREC, and LETREC*. (Yeah, Schemers are funny people. But sometimes they do have a point.)

Understand the difference between Common Lisp's dynamic variables and Scheme's parameter objects (SRFI 39). Compare to EuLisp's DYNAMIC-LET.

Understand why Clozure CL offers DEFSTATIC.

Macros

Understand EVAL-WHEN. Understand the need for something like EVAL-WHEN.

Understand Scheme's expansion process.

Understand hygienic macros, preferably SRFI 72.

Understand why some Schemes use full phase separation, while others like to collapse meta-levels (also).

Understand negative meta-levels. (Once you do, please tell me how they work.)

Control Flow

Understand CATCH/THROW, TAGBODY/GO, and BLOCK/RETURN-FROM, and how they can be implemented in terms of each other.

Understand UNWIND-PROTECT vs DYNAMIC-WIND.

Understand the condition firewall.

Contrast Dylan's, Goo's, and CL's condition systems.

Conclusion

These are just some of the ingredients shared by "mainstream" modern Lisps. They have been developed and refined over the course of 5 decades by some of our best minds. You cannot understand modern Lisp, its history, or contribute to its glorious future without knowing about them.

If you want to learn how to build horse carriages, implement a "LISP". If you want to learn how to build cars, study the items in this list.

</soapbox>

(Update: See the HN discussion for some clarifications.)

4 comments:

fogus said...

Further analogies:

- If you want to learn about genetics, studying the Drosophila doesn't seem right. And the difference between "LISP" and modern Lisps is similar to that between humans and Drosophila.

- If you want to learn how to build a calculator, studying the 1-bit adder doesn't seem right. And the difference between "LISP" and modern Lisps is similar to that between the 1-bit adder and the TI-84+.

- If you want to learn about *modern* architecture, studying ancient Roman aqueducts doesn't seem right. And the difference between "LISP" and modern Lisps is similar to that between moden architecture and ancient Roman architecture.

All study should occur in the large -- great post!

:F

Manuel Simoni said...

Yeah, I know that I'm weak in the argumentative department. ;)

Sam Aaron said...

"Compared to Haskell, Lisp is a big hack."

I'd absolutely love to see a future post expanding upon this sentiment.

Jeff said...

"if you want to learn how to build a car, learning to build a horse carriage doesn't seem right."

Actually it makes a lot of sense. The first cars were in fact called horseless carriages, and learning about wheels, axles, and suspension seems like a reasonable starting point on the way to understanding a car if you don't already know about them.

The same goes for home-grown, minimal lisps. People don't implement these things because they expect to release a new language distribution as much as they want to learn the fundamentals of creating a programming language. Get off your high horse and let people be curious and tinker.

If Lisp is a big hack compared to Haskell, it would be great to understand why. How about showing a couple example problems that require hackery in lisp while remaining elegant in Haskell?