EmacsLisp のマクロは byte-compile することで、ソースコードに埋めこまれる。マクロは defun の代わりに defmacro を使って書く。シンプルなマクロは、関数を書くのと変わらない。一点注意するとしたら、マクロは使われる前に定義しておくこと。
マクロの特徴の一つに、byte-compile 時に式を評価できることが挙げられる。一例として deprecated (廃止された) 関数の呼び出しを書いてみる。
関数を使う
Emacs は進化とともに廃止される関数がある。ここでは interactive-p という関数を取り上げてみよう。この関数は、関数がコマンドとして呼ばれた時は t を返し、関数の中から呼ばれた時は nil を返す。しかし、Emacs 23.2 で called-interactively-p という関数に置き換わった。
古い Emacs でも動作を保証するために、関数 called-interactively-p が存在する時はこれを使い、存在しないなら古くからある interactive-p を使う関数 foo-called-interactively-p を作る。自作の EmacsLisp では called-interactively-p や interactive-p を直接呼ばず、 foo-called-interactively-p を使う。
(defun foo-called-interactively-p ()
(cond
((fboundp 'called-interactively-p) (called-interactively-p 'any))
(t (interactive-p))))
この関数には気に入らない点が二つある。
- Emacs 23.2 以降でソースコードを byte-compile すると、
interactive-pは deprecated だと警告が出る foo-called-interactively-pを呼び出す度に、関数called-interactively-pが存在するかチェックする
マクロを使う
foo-called-interactively-p をマクロで書き直してみる。マクロを使うと、byte-compile 時に評価が出来るので、 called-interactively-p が存在するか否かのチェックは byte-compile 時に行なえる。
また、マクロによって展開されたコードに (Emacs が 23.2 以降なら) interactive-p は含まれていないので、警告も出ない。Emacs の byte-compiler が出す「本当の警告」に集中することができる。
マクロを使って書き直したコードは次のようになる:
(defmacro foo-called-interactively-p ()
(cond
((fboundp 'called-interactively-p) '(called-interactively-p 'any))
(t '(interactive-p))))
byte-compile 時に評価するコードはそのまま書いて、残すコードを quote している。
試しに macroexpand を使って、このマクロを展開してみる (Emacs 24.4 にて評価)。結果は次の通り:
(macroexpand '(foo-called-interactively-p))
-> (called-interactively-p (quote any))
called-interactively-p を使うコードだけが残った。
あとがき
EmacsLisp では、C 言語より高度なマクロを書くことができる。使いすぎは毒だけど、適度に使えばとても便利。バッククォートと組み合わせると、更に便利になる。何か良い例題があったら中級編も書いてみたい。
ちなみに、今回紹介したコードは fcopy.el で使っている。
0 件のコメント:
コメントを投稿