Niyarin's blog

Hylangってのをさわった

Tags:HylangマイナーLisp
2020-12-01


Kobe University Advent Calendar 2020 の1日目の記事です。(書いたのは翌日ですが)
かつてKobe Universityで学生していました。入学前は神戸だしおしゃれな街中の大学だと思っていたのに入学してみたらャンパスが山の中で猪が闊歩していました。その上、立地がアレなせいなのか、大学近くのめしやもうどん屋が一軒しかありませんでしたよ。まあ、いい思い出です。ちなみに今は都会で修士学生しています。

さて、本記事の内容ですがAdvent Calendarみたいな機会でもないと調べないようなことを消費しただけです。HylangというPythonのASTに変換されるS式言語をちょっと触ってみたという程度です。

Hylangについて

思いつくまま、気になったことを動かして納得しました。

CLIツール

Hylangは、PythonのBytecodeを吐くS式言語として知られていますが、Pythonのコードにも変換できるhy2pyというCLIツールが用意されています。(https://docs.hylang.org/en/stable/language/cli.html) Python VM言語というだけでなく、Alt Python的な存在のようです。ただ、コメントとかまで移植されているわけではないので、TypeScriptのように、開発が止まっても変換してその後もメンテしていけるほどのものではなさそうです。そして、普通のスクリプト言語にありがちな、プログラム名だけの"hy"と入力すれば、REPLが立ち上がり、ファイル名をコマンドライン引数として与えればそれを実行してくれます。あとは、hycというhyコードを"pyc"ファイルに変換してくれるツールもあります。

Hylangのmapとかfilterとか

HylangはLispのように記述し、Pythonのように動く言語です。そのため、LispユーザがHylangを書くと思ったように動かないことがあります。Pythonは3系では、map関数はリストではなくイテレータを返すのですが、Hylangもそこは同じです。map手続き/関数は、Schemeでは通常のリストを返し、Clojureでは遅延シーケンスを返すので、2回以上最初の要素を取り出す操作(carとかfirst)をしても結果は変わりませんが、Hylangではこうなります。
=> (setv ls (map inc '(0 1 2 3 4 5)))
=> ls
<map object at 0x7f73689d8e50>
=> (first ls)
1
=> (first ls)
2
=> (first ls)
3
=>

Hylangとマクロ

Hylangは通常のLispのようにマクロが使えます。Clojure等と大差はないです。ここではThreading macroを書いてみます。HylangにはすでにThreading macroがありますので、myを頭に付けていますが。例をみれば分かりますが、Hylangにはletが組み込みのsyntaxではないです。Threading macroよりこちらのほうが優先度が高い気がするのですが、不思議ですね。もちろんletもマクロで書けます。
(defmacro my->> [x &rest rests]
  (if rests
      ((fn [r]
        (if (or (list? r) (isinstance r HyExpression))
          `(my->> ~(+ r [x]) ~@(list (rest rests)))
          `(my->> (~r ~x) ~@(list (rest rests)))))
       (first rests))
      x))

(print (my->> '(0 1 2 3 4 5)
              (map inc)
              list
              reversed
              list))
[6, 5, 4, 3, 2, 1]

Hylangの記号を含む変数の扱い

前のThreading macroのようにHylangは他のLispと同じように多くの記号を変数に使えます。HylangはPython(あるいはそのバイトコード)に変換できる必要があるため、内部で末尾の?は'?'を消して、頭にis_をつけます。
=> list?
<function is_list at 0x7f736889f710>
=> seq?
Traceback (most recent call last):
  File "stdin-15d957270d643dda7d9753401ac9073eb36c061e", line 1, in %lt;module>
    seq?
NameError: name 'is_seq' is not defined

他の記号は'?'ほど人間に易しい変換はされません。
=> set!
Traceback (most recent call last):
  File "stdin-1618e7ba6d820060d00aa35235d94b1aa7db693e", line 1, in <module>
    set!
NameError: name 'hyx_setXexclamation_markX' is not defined

かっことHylang

HylangのリストとPythonの各種コンテナの対応関係についてです。丸括弧すると、Hylang特有のオブジェクトHyExpressionが返ります。角括弧はPythonのリストが返ってきます。
=> '(1 2 3)
HyExpression([
  HyInteger(1),
  HyInteger(2),
  HyInteger(3)])
=> [1 2 3]
[1, 2, 3]

setと辞書はClojureと同じです。
=> (isinstance #{1 2 3} set)
True
=> (isinstance {"a" 1 "b" 2 "c" 3} dict)
True

タプルは特別なリテラルがなく、コンマで作ります。
=> (, 1 2 3)
 (1, 2, 3)

おわりに

HylangはPythonのガワが弱いなと思った人にはとても良いものになると思います。