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]
Python is fine for what it does. But it is not a Lisp-alike; and it is no more like Lisp than any of a half-dozen other popular scripting languages, such as Perl, JavaScript, TCL, or Ruby. Hell,if I recall correctly Perl’s version of Lambda is actually less hamstrung than Python’s.
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.
What I’m saying is this: if you want Lisp, use Lisp. (Or Scheme, or…). If you want something Lisp-like but with a more conventional syntax, there are languages which come a lot closer than Python. Ruby makes metaclass hacking easier, and it’s on much better terms with functional-style coding. TCL is simple and flexible easy to build a domain-specific language on top of. Javascript has better lambda support. Smalltalk probably beats the pants off of all of them in the Lisp-like department, but it’s syntax is weird in it’s own special way.
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.
So is LPC kind of like LISP?
I had to look it up; I was unfamiliar with the name. Not having worked with it I can’t say for certain. But it appears to be quite unlike LISP. On first glance it looks like it takes it’s inspiration primarily from Java (static typing, mix of objects and scalar types) and JavaScript (prototype-based OO).
From what I’ve heard, it’s based on C… if that helps?
Yes, it appeared (from the Wikipedia summary) to have a substantial C lineage.
I understand from Wikipedia that it’s primarily used in MUDs. Is this where you came across it?
Yup. Until about a month (or two) ago, I was a coder on The Two Towers MUD. Well, maybe using the word coder’s a stretch for me; I was more of a descer (good at writing descriptions of objects) than creating interesting code. π
You lost me at infix
But it sounded cool.
Code that writes code seems like some pretty powerful stuff.
Re: You lost me at infix
It is. All the cool kids are doing it.
So Avdi…
What’s really bothering you?
π
ps–I could follow you entirely in a meta way–not having experience with any of these programming languages except perl–but having experience with numerous programming friends who tell me about these languages..
Your idea of Lisp is not that correct
I think your article is heading in the right direction, but there are some misunderstandings of Lisp:
* Everything is a list. That’s wrong. Most Lisp dialects have lots of different data structures. These are not built out of lists. Common Lisp has rationals, complex numbers, multi-dimensional arrays, strings, characters, hashtables, streams, error conditions, functions, classes, … and lots of others.
* Macros is an important feature in building languages. But these languages are mostly using the whole Lisp language to be implemented not just macros.
* Control structures aren’t special. That’s wrong. Usually at the core of Lisp are a few special forms. Newer Lisp dialects try to keep these to a minimum. These special forms need to be implemented directly by the compiler and other language aware tools (like code walkers). Other control structures can then be implemented with macros. These macros then expand to programs which are using the basic special forms. You can’t create those special forms yourself. They are hardwired into the language.
* Recursion is encouraged. Yeah. Though Common Lisp has limits which Scheme hasn’t. In Common Lisp one writes recursive, but often in production code recursion is less used (unless you use tail recursion elimination, which is not standard in Common Lisp).
* LAMBDA. Yes. Used to create anonymous functions. If there are variables in the lexical environment, then a closure is created. Closures are anonymous functions plus their environment.
* A functional style is encouraged. All Lisp dialects are full of non-functional features like settable variables, mutable arrays, CLOS objects and so on. For many functional operations there are also state changing variants.
* You can’t examine a functions code programmatically. As in Common Lisp. In Common Lisp functions are compiled to machine code mostly. There is no standard way to retrieve the source of a function and change it.
Though I agree with your main statement: Any Lisp dialect and Python are very different.
Re: Your idea of Lisp is not that correct
He clearly meant control structures aren’t syntactically special, they look like any other function call, and he’s right.
Re: Your idea of Lisp is not that correct
But they don’t look like ordinary function calls.
A function call looks like this:
(foo arg1 arg2 … argn)
This is the syntax for the FLET special form:
( flet ((function-name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration* form* )
Python is most definitely not Lisp.
Python can leave people with a warm fuzzy feeling that things ‘just work’. Some people, after using a Lisp, or lisp-like language such as Scheme, are pleasantly surprised at getting ‘the warm fuzzies’ when programming in Python. Maybe that’s where some of the comparisons come from.
– Paddy.
Cut Peter Norvig some slack will you
The original article is tryinf to teach Python to the Lisp programmer specifically. He is trying to meet the Lisp programmer half way. It may not be your preferred way to learn a new language but his intent is not malicious.
– Paddy.
Re: Cut Peter Norvig some slack will you
I never suggested he was being malicious. I used the article as an example of a very common meme in programming circles today, that Python is somehow “almost Lisp” in a special way that no other language is, and that it is a particularly well-suited language for teaching Lisp-style techniques. It is neither.
Out of curiosity, how did you find this entry? I don’t recognize your screen name, and I’ve had some other anonymous comments on this post, which rarely happens. Did someone link to me or something?
Re: Cut Peter Norvig some slack will you
On how I found your post:
I’ve read and helped posters on comp.lang.python for some time, and thought I’d branch out and politely join in on any Python related blog posts where I thought I could.
I intend from the start to be polite and refrain from any slanging matches, and just see how it feels after a few months.
I use a rather long google blog search to home in on interesting blog posts.
– Paddy.