Emacs Lisp Hash-table in elisp
Hash-table の C のソースを眺めているうち、 elisp でハッシュテーブルを実装すると理解が深まる気がした。
若干遅いだろうが、手を動かすのも大事。
その前に準備。前回書いた skk 辞書をパースする関数は、特定のハッシュの実装(emacs lisp 組み込みのハッシュテーブル)に依存したコードになっている。これだといろいろハッシュテーブルを実装してみるたびに、この関数のコピーを作らなくてはならず、面倒。
クラスのある Java だと、おそらく共通のインターフェースでも取り出してやるだろうが、Emacs Lisp はオブジェクト指向言語ではなく(Common Lisp ならば CLOS がある)、かつ、マクロという別の手段がある。マクロの場合、そのままでは重複してしまうコードの断片をまとめる。
というときにちょっと elisp のマクロと Common Lisp のマクロの違いに引っ掛かった。マクロは新しい構文を作って重複を省くことができるが、マクロで新しい構文を作る、といっても Lisp にはカッコしかない。例えば Common Lisp のマクロ with-open-file だと、以下のように、
(s p) というカッコ部分で意味のある固まりを作っているので、読みやすい。
(with-open-file (s p)
(do ((l (read-line s) (read-line s nil 'eof)))
((eq l 'eof) "Reached end of file.")
(format t "~&*** ~A~%" l)))
が、elisp ではこのような余分なカッコのつくマクロが定義できないようだ。
(defmacro with-my-buffer ((buffer) &rest body) `(with-current-buffer ,buffer ,@body)) => マクロ展開時にエラー
elisp に Common Lisp の機能を取り込む cl パッケージを使い、defmacroのかわりにdefmacro*を使うことで、ちゃんと定義できる。
(defmacro* with-my-buffer-cl ((buffer) &rest body) `(with-current-buffer ,buffer ,@body)) => ok
カッコの有無はささいな違いに見えるかもしれないが。
だが、この defmacro* 自身も Elisp で書かれている、という事実は、
マクロの本質が所詮、式を変形するだけのもの、ということを示していて面白いと思う。
今後の予定。