hylangからcommon-lisp(sbcl)を呼びだして,common lispの機能を使えるようにした
これは,もともと
で公開されていた hycl というcommon-lispと似た環境をhy上に作るlibraryのフォークで,
これにcommon-lisp(sbcl)をpythonから呼びだす cl4py の機能をclisp.eval_qexpr
という関数名にして導入した.
このlibraryの目玉はdefunマクロで,
(defmacro defun [name arg &rest code]
`(defn ~name [~@arg]
codeをsbcl上のmacroexpandで展開
展開したcodeをhy上のcommon-lisp互換関数で実行
))
することで optima などをのマクロをhyから使えるようになっている.
defunの中でcommon-lispはマクロ展開の時のみに呼びだされるのでnumpyとの混合などもできる.
(clisp.eval_qexpr '(ql:quickload "anaphora"))
(clisp.eval_qexpr '(rename-package 'anaphora 'ap) )
(import numpy)
(defun test_alet2 (x y)
(setq y (+ 10 y))
(numpy.sin
(*
(ap:alet (+ x y) (+ 1 ap:it))
(/ numpy.pi 180)))
)
(test_alet2 49 30)
==> 1.0
clisp.eval_qexprでsbclを直接呼ぶこともできる.
パターンマッチマクロをpython(hy)で使う.
common lispでパターンマッチマクロを実装した optima の主要な機能をhyから使えるようにした.pythonのパターンマッチマクロで pampy というのがあるようだが,それよりも強力.ただしsbclを利用している関係で大文字が小文字に全部変換される制限がある.
(import numpy)
(defun testom4 (u)
(setq p numpy.pi)
(om:match
u
(`(,x 5 ,z) (list x y z))
(`(,x ,p ,z) (list x 2 z)))
)
(testom4 (list/cl 1 numpy.pi 3) )
==> '(1 2 3)
classのプロパティのパターンマッチもできる
(clisp.eval_qexpr `(defstruct numpy.ndarray shape ndim))
とすることでclassのプロパティをSBCLに認識させると,こんなこともできる
(defun testom6 (z)
(om:match
z
((numpy.ndarray shape ndim ) (list shape ndim )))
)
(testom6 (numpy.array [1 2 3]))
==> '( (, 3) 1)
(dir (numpy.array [1 2 3]))
で見れる全プロパティをSBCLに認識させる以下の関数も用意した
(cl_struct_import_obj (numpy.array [1 2 3 ]))
実装
この実装の肝はhyに付属している hy-repr
関数で
sbcl.stdin << (hy-repr code)
ということをするために,cl互換関数をhy上に用意したり, hy-repr
関数の出力をhy-repr-register
でいじったりしている.
制限
- 大文字が全て小文字に変換されるので class MyClassみたいのは class myclassに強制変換される
- common-lisp互換関数で実装していない関数が多数
- optima は動かせたが trivia はちゃんとテストしていないので,できるだけoptimaを使ってほしい.
- hyの評価順序の関係で (ql:quickload "optima") などをライブラリの中(hyclb.cl4hy.hyの真ん中あたり) で実行している.これをしないとtestで失敗する.しかしemacs hy-modeからだと後からql:quickload しても動く.謎な挙動
- pythonのlist => clのvector, pythonのtuple => clのlistとして扱っているが,hyのバグなのかtupleが途中でlistに変換されてしまうことがある.この関係でvectorとlistの区別がちゃんとされていない
- dict = consのlist の扱いが適当になってるので何か統一的な扱いができる方法がいるが思いつかない
- tagbodyの互換関数が変数のスコープの扱いに不安のある実装になっているので,om:matchの中で変数を新しく宣言するのはやめた方が良い.ちゃんとしたtagbodyのhyでの実装を誰か作ってくれないかなあ