(defmacro and
([] true)
([x] x)
([x & rest]
`(let [and# ~x]
(if and# (and ~@rest) and#))))
ClojureはLisp族の一員だ。Lispの特徴の多くは他の言語に入っていったが、データとしてのコード(code-as-data)というLispのアプローチと マクロシステム はいまだLispを他とは異なるものにしている。Clojureはcode-as-dataのシステムを丸括弧で囲まれたリスト(S式)を超えてベクターとマップにまで拡張している。そのため、ベクターとマップもマクロのシンタックスの中で利用することができ、リテラルのリーダー表現などを持っている。
Lispのデータ、したがってLispのコードは リーダー に読み取られる。読み取り結果はフォームで表現されたデータ構造だ。Clojureはコードを表現するデータ構造をコンパイルすることができ、その過程でマクロの呼び出しを探す。マクロを見つけると、フォーム自体を引数として渡してそのマクロを呼び出し、マクロの戻り値をマクロ自身の代わりに利用する。したがって、マクロとはコンパイル時にコードの変換を行うために呼び出される関数だ。コードはデータなので、Clojureライブラリのすべてがその変換処理を支援してくれる。そういうわけで、マクロはLisp、そしてClojureがシンタックスの抽象化をサポートすることを可能にしている。関数を使うのと同じ理由、つまりコード内の重複を削減するためにマクロを使うのだ。マクロは、関数では不十分な状況、例えば評価を制御する必要がある時、識別子を生成する必要がある時などにとっておくべきだ。Clojureのコアとなる構造の多くは、組み込みのプリミティブではなくユーザーが定義できるのと全く同じようなマクロだ。
(defmacro and
([] true)
([x] x)
([x & rest]
`(let [and# ~x]
(if and# (and ~@rest) and#))))
シンタックスクォート(`)を使うことで、マクロが生成するフォームによく似たフォームのマクロを定義するのが簡単になることを覚えておこう。