I am sick of this fucking meme:
Basically, Python can be seen as adialect of Lisp with “traditional” syntax (what Lisp people call”infix” or “m-lisp” syntax). One message on comp.lang.python said “Inever understood why LISP was a good idea until I started playing with python.” Python supports all of Lisp’s essential features except macros, and you don’t miss macros all that much because it does have eval, and operator overloading, and regularexpression parsing, so you can create custom languages that way.
I don’t know where to start. Python is not Lisp. It is not Lisp’s cousin. It is not “good enough” Lisp. Python has never tried to be Lisp, and in fact Guido has done his best to make it less like Lisp. I cannot get my mind around people, including people from the Computer Science community who should know better, equating Python to Lisp.
Which is not to say that Python is a bad language. Python is a perfectly serviceable language. There are a lot of things it’s very good for. Imitating Lisp is not one of them.
I am no Lisp expert, but I know there are certain things which make Lisp (and Scheme, and other dialects – I’m speaking of Lisp in the general sense) Lisp. They include:
- Everything is a list. This is Lisp’s big idea. More than anything else, this is what sets Lisp apart. The fact that everything, including the code, is a list, is what makes it such a flexible language.
- Macros. The “lispy” way to solve a problem is to build a language on top of Lisp, a language which is perfectly adapted to your problem domain. The ability to write code which writes code is essential to this process.
- Control structures aren’t special. Lisp’s control structures – if/else, loop, etc. – are (at least conceptually) just macro calls. There is no difference syntactically between using a built-in control structure and using calling a user-defined macro or function. This enables the language to be extended very flexibly.
- Recursion is encouraged. For any given iterative algorithm, there is an equivalent recursive form. The recursive form is often conceptually cleaner and less bug-prone, although it may at first be less obvious. Lisp encourages the recursive style.
- Lambda. The ability to create anonymous incline closures is an essential Lisp technique, used extensively in Lisp code.
- A functional style is encouraged. Broadly speaking, the functional programming style is characterized by making function calls which return copies, instead of modifying values in-place. This includes building on generic algorithms like
‘fold/reduce’ instead of coding explicit loops with mutable variables.
There are others, but that’s enough for now. Now lets look at those items from the point of view of Python:
- Not everything is a list. Python has a Perl-ish mix of scalar values, objects, and built-in containers. And the code itself is none of these. Yes, you can reference and pass around a function or method as an opaque object; but you can’t examine a function’s code programatically. This alone should set Python apart as fundamentally different from Lisp. The only way to dynamically generate code in Python is to generate text and then eval it – the same way you’d do it in Perl, TCL, Bash, and any number of other pre-existing scripting languages. But there is no way to introspect and/or modify existing code.
- No macros. You can get around this deficiency somewhat with metaclass hacking the same way you would in Ruby (although it’s less convenient in Python); but metaclass hacking has it’s limits.
- Control structures are special. You couldn’t create your own version of, say, a for-loop in Python and call it the same way you would call a Python built-in structure. Python simply doesn’t have the facilities in place, such as macros and call/cc, for implementing new control structures.
- Recursion is discouraged. Guido has made it clear that he has no interest in optimizing tail-calls or doing anything else in Python to make recursion easier to do, because recursion isn’t “Pythonish”. In light of this, how computer science nerds whose first program in any new language is a recursive factorial implementation can rave about Python being Lisp-like is beyond me.
- Lambda. Yes, Python has lambda. It is a sad, hobbled form of lambda, unloved and disowned by it’s creator. The only reason it remains in Python for the time being is because of the popular outcry that arose when he suggested removing it.
- Functional style is discouraged. Quoting Guido, on removing reduce() from the language:
- “So now reduce(). This is actually the one I’ve always hated most, because, apart from a few examples involving + or *, almost every time I see a reduce() call with a non-trivial function argument, I need to grab pen and paper to diagram what’s actually being fed into that function before I understand what the reduce() is supposed to do. So in my mind, the applicability of reduce() is pretty much limited to associative operators, and in all other cases it’s better to write out the accumulation loop explicitly.” [Emphasis mine]
If you really want a Lisp-like language without the parentheses, take TCL for a spin. It’s nothing like Lisp, but it has a similarly clean guiding principle. Where in Lisp everything is a list, in TCL everything is a string – including code. And all the standard control structures – loops, if/else, etc. – are (effectively) just function calls, so you can create new control structures to your heart’s content. In fact, it is one of the most malleable languages I’ve ever used.
But don’t come telling me that Python is the new Lisp.
EDIT: Whenever I read these Python=Lisp comparisons, the bottom line seems to be this: Lisp is dynamic. Python is dynamic. Therefore, Python=Lisp. Which suggests that the writers have either been sadly unacquainted with dynamic languages before encountering Python (e.g. they’ve only worked with C/C++/Java), or they have failed to appreciate and/or fully exploit the dynamic languages they’ve previously come in contact with. It’s amazing, for instance, how poorly understood JavaScrip/ECMAScript is as a language.