This is the 7th day article of iRidge Advent Calendar.
This article introduces Hy, a Lisp dialect implemented in Python.
I'm tanaka.lisp, a server-side engineer at iRidge Inc. I want to see the world of the web and Python, and I work for the Python company IRIDGE.
Suddenly, the language I love so much is Common Lisp. In my business, I read and write Python exclusively, but since Python is not Lisp, I am at the mercy of automatic indentation, and ʻif pred1 and pred2: ...ʻif (and pred1 pred2): ... I'm constantly struggling to write
. Lisper-specific withdrawal symptoms may also appear. I started thinking about sexp, googled with "Hyperspec function name
", and started typing sexp into Emacs. In the end, it's an incomprehensible idea that __Python should become Lisp, which crosses my head during business hours.
Oh, if Python was an S-expression. If you could write an S-expression while riding on the huge standard library group of Python like Language. Oh, oh.
But there is. Such a dreamy, squid language.
Hy
Hy is a Lisp dialect written in Python.
It has a syntax that is strongly influenced by Clojure, and if you get lost in the Hy Style Guide, the order is Python> Clojure> Common Lisp
. So, follow the conventions of that language.
Furthermore, it is possible to interop with Python like Clojure, and it seems that Django application can be written in Hy. Oh, isn't Hyde good with this anymore? ??
By the way, Haskell is famous as a squid language, but Hy's mascot seems to be squid. You're squid. The documentation Three Minutes Tutorial is the most interesting and I recommend you to read it. I was knocked out with this.
Let's install it. Here, install it in the virtualenv environment [^ 1].
[^ 1]: By the way, it seems that it is registered as python-hy
in ubuntu's apt repository.
First, create a venv environment,
$ virtualenv venv
# ...Lots of output
$ cd venv
$ source ./venv/bin/activate
Then install it from github with pip.
(venv) $ pip install git+https://github.com/hylang/hy.git
# ...Lots of output
Hello to start the REPL is after.
(venv) $ hy
hy 0.11.0+320.g5b87932 using CPython(default) 2.7.12 on Linux
=> (print "Hy!")
Hy!
=>
It ’s easy, is n’t it?
Let's see what kind of language it is.
;;;Numerical value and truth value
=> 42
42L
=> False
False
;;;String
=> "forty two"
u'forty two'
First of all, the data structure that can be used in Python can be used almost as it is. However, it seems that writing ,
or :
or delimiters is prohibited.
;;;list. `,`Do not write
=> ["life" "universe" "everything"]
[u'life', u'universe', u'everything']
;;;dictionary.This also does not require a delimiter
=> {"arthor" "dent" "ford" "prefect"}
{u'arthor': u'dent', u'ford': u'prefect'}
And here are the Lisp-specific data types. It seems strange that the symbol display is a Unicode character string.
;;;symbol.The display is a character string, but the type is a symbol properly
=> 'marvin
u'marvin'
=> (type 'marvin)
<class 'hy.models.symbol.HySymbol'>
;;keyword
=> :deep-thought
u'\ufdd0:deep-thought'
;;Symbols that are always unequal to others
=> (gensym)
u':G_1236'
And how, there is no nil
! Ah, God, how do I write an empty list?
;;;no nil!
=> nil
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'nil' is not defined
God "You should use()
!"
I "I see!"
=> ()
[]
In fact, it seems that even Lisp's traditional list notation may ** sometimes become a Python list **.
=> '(a b c)
(u'a' u'b' u'c')
=> (cons 'googolplex (cons 'star (cons 'thinker ())))
[u'googolplex', u'star', u'thinker']
And cons. It seems that Lisp's father John McCarthy pronounced Corn Snake.
=> (cons 'arther 'dent)
(u'arther' . u'dent')
;;;It is OK to write in dot pairs and quote
=> '(arther . dent)
(u'arther' . u'dent')
Since Hy is a Lisp language, function calls are written in Polish notation.
;;;String concatenation
=> (+ "forty" " " "two")
u'forty two'
;;;Four arithmetic operations
=> (+ 1 (* 5 8) 1)
42L
The function definition looks like Clojure. It's always the same as when I just type defun
and get confused.
=> (defn factorial [n]
... (if (<= n 0)
... 1
... (* n (factorial (- n 1)))))
=> (factorial 10)
3628800L
By the way, the list is syntactic sugar for Cons. Lisp code is written in a list. So you should be able to write the code in chords. In Common Lisp, even if you write a program in dot pairs, it will be read properly, but ...
=> (print . ("forty" . ("two" . ())))
forty two
Oh! I'll do it! This paved the way for obfuscation.
As an example of using Python's rich standard library, let's try Examples of communication using httplib with Hy.
;;;import.from can also be imported
=> (import httplib)
=> (setv conn (httplib.HTTPSConnection "www.python.org"))
=> (conn.request "GET" "/")
=> (setv res (conn.getresponse))
=> (print res.status res.reason)
200 OK
Just read it as an S-expression and it's done. This is your chance to migrate your scripts written in Python to Hy.
Now, make sure Hy isn't just familiar with Python, it's also a Lisp companion. For those who aren't Lisper, macros here aren't C macros, they're the ones that manipulate the abstract syntax tree. Rust, Nim, Scala, etc. have this feature. By the way, Hy [already has an anaphoric macro] as a contributor module [http://docs.hylang.org/en/latest/contrib/anaphoric.html).
As an example, for the time being, I thought that anaphoric macros are appropriate because the benefits are easy to understand. An anaphoric macro, for example, allows you to refer to the value of an expression in the conditional part of an if statement from behind. For details, see [Corresponding Chapter of On Lisp](http://www.asahi-net. Please also read or.jp/~kc7k-nd/onlispjhtml/anaphoricMacros.html).
For the time being, I will implement it by copying from On Lisp and use it.
=> (defmacro aif [test-form then-form &optional else-form]
... `(let [it ~test-form]
... (if it ~then-form ,else-form)))
=> (aif (+ 1 2)
... (print 'cheese it it))
cheese 3 3
You can refer to the evaluation result of the conditional expression of the if expression (here, ʻaif) in ʻit
. Let's see how the expression is converted
;;;The output is hand-formatted for easy viewing
=> (macroexpand '(aif (+ 1 2)
... (print 'cheese it it)))
((u'fn' [](u'setv' u'it' (u'+' 1L 2L))
(u'if' u'it'
(u'print' (u'quote' u'cheese') u'it' u'it')
u',else_form')))
The symbol is displayed as a Unicode string, which is awkward, but it looks good.
What makes me happy about this
--Already calculated value (when conditional branching) can be used --You don't have to write the same conditional expression over and over again
That is a nice point.
As an example, consider the case where a conditional expression is an expression that takes a lot of time.
=> (reduce (fn [a b](+ a b)) (range 1 1000000000))
499999999500000000
When I hit this formula for the time being, the REPL was silent for about a minute: sob: **. When you want to use this result many times
(aif (reduce (fn [a b](+ a b)) (range 1 1000000000))
(print (+ it it))
It is a dimension that can avoid multiple calculations if it is set as such. It is a story that you should assign it to a local variable, but if you write an anaphoric macro, the creation and assignment of the local variable will be done automatically behind the scenes.
Finally. You can convert Hy code to Python code. By doing this, you can eliminate the danger of Hy that is held by REPL ~ ~ when developing, write in Hy and convert to Python when committing ~ ~.
If you try it, the overhead of actually parsing will be reduced, or there will be no lag until the result is returned.
(venv) $ cat upto.hy
(defn up-to-n [n]
(list-comp n (n (range n)) (= (% n 2) 0)))
(print (up-to-n (integer (raw-input "input number: "))))
# upto.Convert hy
(venv) $ hy2py upto.hy > upto.py
#Conversion result
(venv) $ cat upto.py
from hy.core.language import integer, range
def up_to_n(n):
return [n for n in range(n) if ((n % 2L) == 0L)]
print(up_to_n(integer(raw_input(u'input number: '))))
(venv) $ python upto.py
input number: 10
[0, 2, 4, 6, 8]
Introduced the Lisp dialect Hy written in Python.
--Hy installation is easy with pip
--Hy syntax is simple, convenient, and S-expression
--Hy can access Python assets
--Hy has Lisp metaprogramming power
--Hy code can be converted to Python code to make it faster
It is an impression that I touched and wrote that it is a fairly well-made language.
This article was originally intended to be published a year ago [^ 2]. However, after all, when I got to know the world of Python and touched it, I could guess the background of Hy's way of doing things. Perhaps it was the right time to get used to Python.
[^ 2]: I was thinking of announcing it in the in-house LT, but it seems difficult to do it in this article LT ...
I think Hy itself is a pretty good language, so Lisper brothers who are engaged in the Python industry consider introducing it when they say, "I have to use Python, but the syntax is not an S-expression." How about trying it?
Recommended Posts