Alexandriaとは
AlexandriaはCommon Lispのユーティリティライブラリです。必須ではないけれどあったら便利な関数やマクロが収録されています。
ここではAlexandriaに収録されている関数やマクロの中で、割と日の目を見ないものをみっつ紹介します。本当は真面目にド定番なのを紹介した記事を書いていたのですが、Firefoxさんが固まって電子の海へ還っていきました。正直ワロタ。
destructuring-case
destructuring-caseはcaseとdestructuring-bindの組み合わせです。
destructuring-case keyform &body clauses
という感じのマクロで、それぞれのclauseは
((case-keys . destructuring-lambda-list) form*)
という構造になっています。
手っ取り早く説明すると、keyformのcar部に対してcase-keysを使ってcaseでマッチングさせ、マッチしたらdestructuring-lambda-listに従ってcdr部をdestructuring-bindで分解し、その中でformを実行します。言葉にしたら訳わかりませんね。こんな感じです。
(destructuring-case '(:x 0 1 2)
((:x x y z) (list x y z))
((t &rest rest) :else))
;=> (0 1 2)
(destructuring-case '(:y 0 1 2)
((:x x y z) (list x y z))
((t &rest rest) :else))
;=> :ELSE
リストに対する簡易なパターンマッチングという感じですが、keyformのcdr部を無視したい場合のタイプ数とかを考慮すると、あれっ? 意外と使いにくい? と思えてくる一品です。多分気のせいじゃないです。
format-symbol
マクロを定義するときに
(intern (format nil "~a-~a" x y) :package)
なんて感じのコードを書いたことは割とあるんじゃないでしょうか。
format-symbolを使えばこう書けます。
(format-symbol :package "~a-~a" x y)
あんまり差がないように見えるのは心が汚れているせいです。ピュアな人には違いが分かってもらえると思います。
map-iota
loopはあんまり好きじゃないけどdotimesもどうよ、な人に新たな救世主が!
(loop for n to 10 do (print n))
(dotimes (n (1+ 10)) (print n))
がこう書けます。
(map-iota #'print 10)
Alexandriaのiota関数を使って作ったリストに、第一引数の関数を適用するって感じです。戻り値は第二引数で固定なので、副作用が目的の場合に使うと良いでしょう。
まとめ
割と誰得っぽい風味のアイテムをみっつ紹介しましたが、Alexandriaにはwith-gensymsやonce-only、define-constant、compose、curry、mappendなどの定番かつ便利な関数やマクロも多く収録されています。使っていない人は一度試してみてください。使ってる人も、コードやドキュメントを読み返すと、意外な発見があるかもしれません。