4 ms·
> Python is a good enough Lisp, as Peter Norvig has concluded. And it’s got all batteries included. Ain‘t nothing it can’t do. I almost agree, but Python fails
by ryukafalz 3y ago
> Python is a good enough Lisp, as Peter Norvig has concluded. And it’s got all batteries included. Ain‘t nothing it can’t do.
I almost agree, but Python fails in one area, which happens to be my current area of interest. It doesn't have sufficiently strict encapsulation to support object capabilities[0] at the language level.
JavaScript, on the other hand, does[1] - so you don't necessarily need Lisp for this, but I do enjoy the parentheses. :)
[0] http://habitatchronicles.com/2017/05/what-are-capabilities/ http://habitatchronicles.com/2017/05/what-are-capabilities/
[1] https://medium.com/agoric/pola-would-have-prevented-the-event-stream-incident-45653ecbda99 https://medium.com/agoric/pola-would-have-prevented-the-even...
- hajile 3y agoIt falls short in several key ways. First, it has no macros. The ability to metaprogram in Python is practically nonexistent compared to Lisp. Second, it has no usable lambda (being limited to a single expression in a non-expression oriented language. Most lisps heavily rely on the ability to pass around arbitrary functions whether named or not. Third, it is slow. Your toy scheme implementation is probably going to be about as fast as Python and something like SBCL/Common Lisp will be literally 3-400x faster and that’s without mentioning that Python is limited to green threads. There’s no reason to limit yourself to such a slow language Fourth, it lacks the interactive development environment of Common Lisp. Sue it has a REPL, but you can’t do all your coding against a live instance with fine-grained control of your updated code. This is hard to describe, but it’s a massive differentiator.
- jsmith45 3y agoPython does have plenty of metaprogramming capabilities, they just are more complex to use than a macro system. One simple, but highly limited system is metaclasses. Similarly weak but existing features include creating classes at runtime, and adding new methods to classes at runtime. A far more powerful system is compiling source to AST, which can then be manipulated, and finally compiled to bytecode. This allows arbitrary metaprogramming, but is certainly fairly complex. One could even use it to implement a macro-like system by coding up a new finder that uses a new SourceFileLoader subclass that overrides the (accidentally undocumented!?) `source_to_code` method. In there, one can compile to ast, transform the ast, and then compile the ast to bytecode. (The method was documented back in 3.4 by way of being documented on a ancestor abstract base class, but that documented ancestor was changed to be static in 3.5, leaving this method seemingly accidentally undocumented.) For the transform the AST step, one might look for apparent function calls to special macro functions, and instead call those macro methods as AST time passing in the AST of its arguments, receiving back as AST that you place in the tree replacing the function call. There is some trickiness here. For example, it is much easier if the macros are defined in another module so that they can already be compiled, and thus available while importing a module that uses them. It should also be possible to handle macros defined in the same file by stripping out non-macro function definitions, and non-imports from top level statements, compiling that, and then using the result while processing the whole (unstripped) AST, and then finally compiling the result. Of course such a system is significantly more complicated than with a lisp, but it is still possible. Its load time performance is also not likely to be especially wonderful, but python is not exactly a performance powerhouse.