特別休暇
ずっと働き詰めでした。たまには自分にお休みを与えてもいいと思いました。夏季臨時休暇を利用してtcl/tkを、自作Lisp Easy-ISLisp(以下、EISL)にライブラリとして組み込みました。
C言語方式
Common-Lispのtcl/tkライブラリを調べてみますと、wishをプロセス間通信で呼び出す方式と、C言語で直接呼び出す方式があるようです。M.Hiroiさんのtcl/tkのページにはC言語で呼び出す方法が説明されていました。(M.Hiroiさんのページ)http://www.nct9.ne.jp/m_hiroi/tcl_tk_doc/tcltk305.html EISLのCラッパーの機能を利用、C言語を介して呼び出す方式としました。例えばcanvasを呼び出す関数は次のようになっています。
(defun tk::canvas (obj :rest l)
(let ((opt (tk::option l)))
(c-lang
"strcpy(buff,''canvas .'');
strcat(buff,str_to_lower(Fgetname(OBJ)));
strcat(buff,Fgetname(OPT));
strcat(buff,''\n'');
Tcl_Eval(interp,buff);")))
ライブラリは予めコンパイルしておく必要があります。
(compile-file "library/tcltk.lsp")
再帰図形
おおよそ必要な関数が揃いましたので、再帰図形を描かせてテストすることとしました。シェルピンスキーのギャスケットです。
コードは次のようになります。
(import "tcltk")
(defun recur ()
(tk::init)
(tk::canvas 'c0 '-width 600 '-height 600)
(gasket #(300 0) #(0 600) #(600 600) 10)
(tk::pack 'c0)
(tk::mainloop))
(defun midpoint (a b)
(let ((a0 (elt a 0))
(a1 (elt a 1))
(b0 (elt b 0))
(b1 (elt b 1)))
(vector (+ (min a0 b0) (abs (quotient (- a0 b0) 2)))
(+ (min a1 b1) (abs (quotient (- a1 b1) 2))))))
(defun draw-triang (a b c)
(let ((a0 (elt a 0))
(a1 (elt a 1))
(b0 (elt b 0))
(b1 (elt b 1))
(c0 (elt c 0))
(c1 (elt c 1)))
(tk::create 'c0 (line a0 a1 b0 b1 c0 c1 a0 a1) '-fill 'green)))
(defun gasket (a b c n)
(cond ((= n 0) t)
(t
(draw-triang a b c)
(draw-triang (midpoint a b) (midpoint b c) (midpoint c a))
(gasket a (midpoint a b) (midpoint a c) (- n 1))
(gasket (midpoint a b) b (midpoint b c) (- n 1))
(gasket (midpoint a c) (midpoint b c) c (- n 1)) )))
これを読み込んで(recur)関数を実行するとあのシェルピンスキーの再帰図形が現れます。
再帰図形の思い出
初めてこの手の再帰図形を見たのはウインストンのLISP本でした。c-curveを描くものでした。昭和58年ころのことでした。あれから40年ほど経過し世の中も変わりました。当時は記号処理のできる言語というとLispくらいしかありませんでした。今やPythonやら、Rubyやらテンコ盛りです。それにしてもLispで書かれたgasketのコードを眺めてると再帰にもっとも馴染んでる言語は今でもlispではないかと思います。
ドキュメントなど
EISLはOSSです。Githubにて公開しています。ライブラリの使い方についてはdocumentフォルダーの中のTCLTK.mdにあります。追々、記述を充実させていく予定です。