Pythonで書かれたLisp Hy | たけおか ぼちぼち日記

たけおか ぼちぼち日記

思いついたらメモ

これは Lispアドベント・カレンダー2020 DEC.21.2020 です。

AI言語は、LispとPrologに決まってるやろ〜 というあたくし。
Pythonって、なんや。遅いインタープリタ、ナメてんのか…

だが、Pythonって、ライブラリ呼ぶだけでイロイロできてしまう…
ライブラリの呼び出し方は、ググってコピペでOK\(^^;/

でも、やっぱり Lisp 使うぜ。
ここで軟弱な Pythonで書かれたLispを使おうかなと…

「Hy」 という軟弱 Lisp

Ubuntu 18.04.5 LTSでは、
$ sudo apt install python3-hy
で、インストールできました。

$ hy
で起動。



なんと、setq が無くて、代わりが setv。
マクロはある。
setqを defmacro するしか…
「〜」がCommon Lispの「,」にあたるようだ。



=> (defmacro setq [var val]
... `(setv ~var ~val))

=> (setq a 'asd)
=> a
'asd'
=> (setq a '(q w e))
=> a
('q' 'w' 'e')




関数でも defun するか…
あれ、defun じゃなくて、「defn」 か


=> (defn fact [x]
... (if (<= x 0) 1
... (* x (fact (- x 1)))))
=> (fact 3)
6
=> (fact 6)
720




よーし、テールリカーシブな実装になってるか、調べたろ…


=>(defn aho []
... (aho))
=> (aho)
Traceback (most recent call last):
File "/usr/lib/python3.6/code.py", line 91, in runcode
exec(code, self.locals)
File "<input>", line 1, in <module>
File "<input>", line 2, in aho
File "<input>", line 2, in aho
File "<input>", line 2, in aho
[Previous line repeated 988 more times]
RecursionError: maximum recursion depth exceeded
=>


あ、アカン、素朴すぎる… \(^^;/




fnで無名関数は作れる。
でも、クロージャは作れないようだ…アカンやん。
公式ドキュメントを「closure」でサーチしても、出てこないから、無いんだろう…


=> (setv xxxx
(do(setv lll ())
(fn [x]
(if (= x 0) (setv lll ())
(setv lll(cons lll x)) (print lll)))))

... ... ... ... => => (xxxx 0)
[]
=> (xxxx 2)
Traceback (most recent call last):
File "/usr/lib/python3.6/code.py", line 91, in runcode
exec(code, self.locals)
File ">input>", line 1, in
File ">input>", line 5, in xxxx
UnboundLocalError: local variable 'lll' referenced before assignment
=>


上は、Common Lispならば こう書くやつ (if 0は省略)

(setq xxxx
(let((lll ()))
(lambda (x)
(setq lll (cons x lll)))))

* (funcall xxxx 'q)
(Q)
* (funcall xxxx 'q)
(Q Q)
* (funcall xxxx 'q)
(Q Q Q)


hyでは、setvはバインドを行う。
doは Common Lispの prog と同等らしい。
ちなみに、バインドを起こさず、set のみ行うプリミティブは、hyには無さそうなのだが…




あと、Hy のリテラルは下の表の通り、Pythonのものと対応している。
あたくしは、Python は辞書がなければ使い物にならないと考えており…
Hy の世界でPython 辞書が扱えるのは、なかなかよろしい。
だがっ! 記号(Symbol) が無いではないか。
すべてストリングかよっ。Lispなのに記号が無い。記号処理言語なのに記号が無い…
うーん、虚しい…
多分、自分でオブジェクトを独自に作ると、GCが面倒くさくなると考えたんじゃないかな…虚しい…

この表は
https://docs.hylang.org/en/master/tutorial.html
からコピーしました。
--
Here’s an example of Hy code for each type and the Python equivalent.



HyPythonType
11int
1.21.2float
4j4jcomplex
TrueTruebool
NoneNoneNoneType
"hy"'hy'str
b"hy"b'hy'bytes
(, 1 2 3)(1, 2, 3)tuple
[1 2 3][1, 2, 3]list
#{1 2 3}{1, 2, 3}set
{1 2  3 4}{1: 2, 3: 4}dict

--


Python の関数を呼び出す。
オブジェクトは、Pythonのネイティブのままだから、Python関数呼び出しは楽でいい。

標準的なライブラリを呼び出す。

=> (import datetime)
=> (setv ttt (datetime.datetime.now))
=> ttt
datetime.datetime(2020, 12, 22, 20, 48, 31, 987827)




自作のPython関数。 "aho.py"ファイルとして下記を作る。

# aho.py
def aho1(d):
print('a')
for k in d:
print('key='+ str(k) +', value=' + str(d[k]))
## aho1({1:11, 2:22, 3:33})


そしてhy から呼び出し。

=> (import aho)
=> (setv dd {'a 'asd 'b 'qwe 'c 'zxc})
=> dd
{'a': 'asd', 'b': 'qwe', 'c': 'zxc'}
=> (.aho1 aho dd)
a
key=a, value=asd
key=b, value=qwe
key=c, value=zxc
=> (setv dd1 {'a 1111 'b 222 'c 333})
=> dd1
{'a': 1111, 'b': 222, 'c': 333}
=> (.aho1 aho dd1)
a
key=a, value=1111
key=b, value=222
key=c, value=333


まぁまぁいいね。

以上。