Try Hy(try-hy.appspot.com) |
[]+[] -> error ...
=> (+ [] [])
[]
As in Lisp, commas aren't needed to separate list items. []+1 is parsed like [] followed by positive 1 (+1), which is why it ends up executing even though it's infix notation passed into a prefix-notation parser.Also, Hy's lexing appears to have an interesting feature where you don't always need a space to delimit things, so []+1 is automagically broken up into [] and +1. Here are some other examples where it breaks things up:
=> []"foo"3"hey"["wakka""wakka"]
[]
u'foo'
3
u'hey'
[u'wakka', u'wakka']
=> (+[1][2][3])
[1, 2, 3]
So without parens, []+1 is like []; +1; in Python and prints out the same result. With parens, the first token of ([]+1) is treated as a function (as would be typical in Lisp) so it tries to execute the Python [](+1), and you get the error that [] isn't callable.So []+1 ran, but not for the obvious reasons. I'm basically poking at the REPL like you to try and puzzle this out; if you want to dig further, you could look at Hy's docs or source or contact the folks that wrote it.
Edit: an additional detail, not sure if it's informative or just confusing-- "+ 1" is apparently lexed by Hy as two items, not as positive 1:
=> [] + 1
[]
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name '+' is not definedHere's more information: http://docs.hylang.org/en/latest/tutorial.html
http://www.youtube.com/watch?v=ulekCWvDFVI
and a quick 5 minute lightning talk:
http://youtu.be/1vui-LupKJI?t=16m13s
(Creator here)
Hack on!
Hy has come a ways since then even. Shortly after that talk we added succinct syntax aliases for QUOTE and QUASIQUOTE. And we added a nice clojure-inspired core library.
It's a cool little language. Fun to hack on. You could learn a few things if you do. And I do hope that we can start help creating documentation for the Python AST module via this project.
[1] http://pyvideo.org/video/2328/hy-a-lisp-that-compiles-to-pyt...
Happy to answer questions.
I also really like the idea of being able to extend the language with macros. Hy certainly seems like a good start towards a language like this.
My favourite one to hack on (owing to my PHP ability) is Pharen[0]. Very neat little Lisp that compiles down to PHP, which is very fun to play with. I highly suggest giving Hy a go if you're a Pythonista, as you can learn a lot about programming in general by seeing how these sorts of languages map to the host. Very fun to hack on, too!
File "<input>", line 1, in fac
File "<input>", line 1, in fac
File "<input>", line 1, in fac
RuntimeError: maximum recursion depth exceeded
=>Reverse Polish notation's even cooler property is that, in addition to the unambiguity, it can easily be evaluated from left to right with a stack: If you see a operand, push it onto the stack. If you see an operator, pop two operands off the stack, compute, and push the result onto the stack. By the end you'll have a one-element stack with your result.
Really what we're seeing here, though, is a language without infix operators: all functions are of the form "<name> <operand1> <operand2>…", but grouping still works as expected.
Thanks matchu for the additional info on RPN. I didn't know about the stack evaluation benefit, that is very cool.
Some hilariously bad implementations in that file, but it's just for fun.
P.S. The lisp-1 nature of scheme isn't why hygenic macros are important there, it's really a bit of a red-herring, since macros in common-lisp can (and do) use (flet) and (labels)
Hy isn't trying to be CL or Scheme. It is still after all, Python. However a homoiconic front-end to Python has interesting implications for a language like Python. Macros in Hy are almost like a template language for Python ASTs. You could replace the namedtuple implementation with a Hy macro. If Python didn't have a `with` keyword you could implement it as a Hy macro. I'm sure there may be more.
Python's not a lisp under the hood. However it does benefit from some of the superficial features of a homoiconic transpilation. :) </cheeky>
Firstly, AST visitors in Python (or whatever) are clunky and lots of code to do what you say. Hell, I think that it's borderline unpythonic.
You have to consider lots of things, such as whether or not you can put an stmt where you're inserting code, and write a lot of, frankly ugly, Python code to do it.
Hy macros (and really Lisp macros) that are first-class members of the language are nice, because they're a lot more clean to write.
In addition, since Hy does some nasty stuff under the hood to generate clean Python AST, you can do stuff like:
(print (if true true flase))
(Ok, that's a lie, since it'll do "print True if True else False", but if that had a (do) around everything, it'd still work by mangling the expression - just too tired to write that example right now :) )Fundamentally, a Hy macro IS an AST macro, just on the parsed and tokenized Hy code (which turns into AST), rather then fiddling with Python AST (which isn't even a stable interface).
That answer the question? :)
In Python, the AST approximates this. Perhaps I'm lax in usage, but I think there's a continuum of homoiconicity - some things (like C) have no language functionality to deal with their own source code. Other languages (like CL) are very good at this, since you write the language in it's own data structures. Other languages (like Python, or Racket) aren't homoiconic, but they approximate what makes homoiconicity special.
The syntax objects hold more information about scopes, namespaces and the like than they would were they just datum(s?).