From Peter Norvig:
Basically, Python can be seen as a dialect of Lisp with “traditional” syntax … 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 regular expression parsing, so some — but not all — of the use cases for macros are covered.
Source: Python for Lisp Programmers
I think that’s a rather useless statement; Python is like Lisp in the sense that most languages are alike…
Decorators fulfill the role of macros to much extent, so yes – they are not missed.
I think this is more than an empty comparison. Norvig comments on how macros are commonly used in Lisp and points out the Python counterparts. And if you follow the link to Norvig’s article, you can see more comparisons between the languages.
True, you could compare any programming language to any other. But some languages are closer to Lisp than others. And even for languages not close to Lisp, the comparison could be interesting.
Having been sort of half aware of Lisp for a long time (tiny bit of programming in it in the late 1970s; a rather inspiring lecture by Jerry Sussman in around 1980; bit more AutoCAD Lisp, though mostly just reading it, around 2000) and having read most of SICP at one time of another I’m sort of primed to the ideas. I did a year or so of Python programming without really connecting it but more recently I’ve been playing with JavaScript a bit and finally really got to understand closures properly – something which I’ll probably take back with me next time I do some Python programming. Still, I’m thinking I really ought to just cut out the middle man and start using Lisp (or Scheme or something).
Functions returning functions that carry around the scope from their definition would, for me, distinguish (modern-)Lisp-like from non-Lisp-like languages.
I’m currently taking an online course at udacity.com being taught by Peter Norvig. The intent of the course is to introduce people with beginner-level Python knowledge to more complex problems and teach them tools and problem solving methods.
We’re in the third week now. In the second week he introduced eval() to create lambda functions in order to solve cryptarithmetic problems (e.g. YOU + ME = LOVE).
I’m mentioning this because I found it weird that he introduced eval() at all in such a course, although in this light it makes a bit more sense.
On the other hand… she wore a glove. McCarthy once said something to the effect of,
Christopher, in Python, through compile – data becomes code; through inspect – code becomes data. Python however is Python and Lisp is Lisp.
Python also lacks full support for continuations.
In terms of macros, Lisp and Scheme seem to have about half a dozen subtly different ways of implementing them…
The interesting bit seems to be largely being missed. Any language can be evaluated as a skin on Lisp in principle. Not interpreted in Lisp but the other language syntax producing and running Lisp code. Reader macros are part of the magic. This is also different than but more akin to a transpiler except that execution of generated Lisp happens immediately inline.
Lisp allows you to have custom static analysis using macros, although I wonder how common it is. Writing eval / apply is much easier in Lisp than in Python, and by changing a few things you can have a custom contract/type system. Even better you can generate code that can’t have errors in it by using a higher level Lisp (like logic/constraint programming). I’ve heard that Dependently Typed languages / proof-checkers could generate Lisp too.
Another way of dealing with errors in Python/Lisp is to build a simple reloader that calls reload and copies data, and goes back to a “working” state. You might need a some ways to verify that the data is not in an invalid state though, or always serialize all your data periodically.