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)) => マクロ展開時にエラー

elispCommon Lisp の機能を取り込む cl パッケージを使い、defmacroのかわりにdefmacro*を使うことで、ちゃんと定義できる。

(defmacro* with-my-buffer-cl ((buffer) &rest body)
  `(with-current-buffer ,buffer
     ,@body)) => ok


カッコの有無はささいな違いに見えるかもしれないが。


だが、この defmacro* 自身も Elisp で書かれている、という事実は、
マクロの本質が所詮、式を変形するだけのもの、ということを示していて面白いと思う。

今後の予定。

  • elisp でハッシュテーブルを実装する。ハッシュ関数は sxhash を使う。
  • Common Lisp のハッシュテーブルを調べる。ソースがあるのだと clisp とか sbcl?
  • SKK 辞書については、ランダムな文字列ではなく、相当に偏りがあるデータだ。sxhash 関数はどのような入力でもある程度ばらつくようにできているが、ある意味手抜きであって、SKK 辞書専用のハッシュ関数(完全ハッシュ関数)を作ることは常に可能なはず。
  • gauche のハッシュテーブル。