A week with Hy
nextjournal.com
nextjournal.com
It's been phenomenal so far and I want to finish my comment the same way the author finishes his blog post:
> It stands on the shoulders of a giant (Python) and balances another giant (Lisp) on top of this. Better is better, guys. pip install hy.
(main
(linenumber 10 (print "hello world"))
(linenumber 20 (print "Hey!"))
(goto 10))
More seriously, is Hy anything more than writing Python with some parentheses there and there?Coding in Lisp has nothing to do with putting parentheses everywhere but rather with thinking in some specific way. For instance, I know that I am ready to code something in Lisp when I see my whole task as a sequence of CONS, but how could Hy truly implement such a thing as long as it relies on Python lists?
Seems pretty neat, if you ask me.
=> 'foo
HySymbol(u'foo')
Assignment and conditionals are expressions, however assignment returns None. => (setv bar (setv foo (if True True False)))
=> (type bar)
<type 'NoneType'>
Quoted expressions evaluate to Hy AST. => '(+ 1 2 3)
HyExpression([
HySymbol(u'+'),
HyInteger(1L),
HyInteger(2L),
HyInteger(3L)]
)
So it's kind of a frontend for the Python compiler, it goes:Hy AST -> Python AST -> Python bytecode
=> 'foo
foo
(or, at worst FOO rather than foo). => '(+ 1 2 3)
(1 2 3) (defmacro print-loop (line-start line-inc strings)
(let ((i line-start))
`(main
,(mapcar (lambda (x) `(linenumber ,(setq line-start (+ line-start line-inc)) (print ,x))) strings)
(goto line-start))))Why would one want such a thing? Well, s-expressions confer many advantages (and of course, some disadvantages - it's good to have a choice!)
- It makes it easy to write code that writes code, which is useful because it affords "compile-time" abstractions with no runtime performance penalty (in lisp terms, "macros").
- If you're comfortable with a structure editor, it enormously lowers the friction involved in refactoring.
- It allows everything to be an expression:
json.loads(with f as open("file.json"): f.read()) #doesn't work
(json.loads (with [f (open "file.json")] (f.read))) ;works
- It effectively removes all restrictions based around things fitting on a single line - lambdas are the canonical example. (tagbody
10 (print "hello world")
20 (print "Hey!")
(go 10))E.g. consider xrange() vs (Python 2) range().
(Hell is debugging someone else's LISP macros. I have a very old LISP program, a theorem prover, I've tried to convert from Franz LISP, a Maclisp dialect, to Common LISP. I worked on it years ago. I just can't fix some of the bugs. The original authors of the part that doesn't work right are long dead.)
def prepare_target(y):
if hasattr(y, "values")
return target.values.reshape(-1,1)
else:
return target.reshape(-1,1)
Shouldn't that be def prepare_target(y):
if hasattr(y, "values")
return y.values.reshape(-1,1)
else:
return y.reshape(-1,1)Python is already fairly OK, use decorators instead of def macro, metaclasses if you need to get into head-scratching territory etc. Use the 4 argument form of the type function, belabor __new__ etc it will still be readable instead of a pile of nail clippings
Give it a try! It is really fun and significantly lowers the barrier off entry to the land of lisp!
I'm curious how hy modules can be imported in python directly.
https://github.com/hylang/hy/blob/master/hy/importer.py#L132