Python instead of Lisp

:: computer, lisp

Lots of people, even famous Lisp hackers, like to claim that ‘Python can be seen as a dialect of Lisp with “traditional” syntax’.

Being famous does not make them right.

Python is nothing like Lisp

Expression language. Lisp is an expression language: everything in the language is an expression and has a value, and there is no distinction between expressions and statements, because there are no statements. Python is not: it has expressions, such as 2+3, lambda x: x*2 and statements such as x = 3. If expressions and statements are different things then writing macros and any kind of general-purpose lambda becomes very difficult.

Conses. Lisp has conses, Python does not. Conses are not everything1, but unless you have them you can’t implement them reasonably, and they are extremely useful data structures for many purposes. In particular for conses to be useful you need two things:

  • a good syntax for them and for lists built from them;
  • good performance — conses should be extremely cheap, so you can’t implement them as a special case of some heavyweight data structure such as a Python list, because there is an enormous header.

This means that conses need to be wired into the language: you can’t take a language without conses and add them, because even if you can get the first (you can’t in Python) you can’t get the second.

Symbols. Lisp has symbols, Python does not. You can use strings, and this works sometimes.

Lambda. Lisp has lambda, Python has an extremely limited version. Not being an expression language (see above) and the lack of scoping and block constructs in Python cripples its lambda.

Source code available as a low-commitment data structure. Lisp has this, Python does not. ‘Low-commitment’ means that it is available before it has been decided what it means, but after it has been turned from a stream of characters into something more interesting. This matters because it makes macros possible: macros which work by transforming streams of characters are doomed to the sort of unspeakable horror of which Jinja2 is a good example, while macros which work after it has been decided what the code means then can’t make their own decision about what it means, which is half the point of macros.

Scoping. Lisp has a multiplicity of scoping constructs and all modern Lisps have lexical scope, with some (Scheme) extending this to control constructs. Binding and assignment are irreparably confused in Python: scope does not work properly and this can never be fixed. A language which requires a global declaration is not going to be fixed by adding nonlocal.

Macros. Lisp has them, Python doesn’t. Since macros are the point of Lisp, it is really hard to see how the above quote makes any kind of sense.

There is a terrible truth about the percieved arrogance of Lisp hackers that it has taken me a long time to understand. The arrogance is justified: Lisp is, in fact, a better programming language.

  1. In particular conses are not a useful universal data structure in the way that, perhaps, early Lisp people thought they were.