(defmacro and
([] true)
([x] x)
([x & rest]
`(let [and# ~x]
(if and# (and ~@rest) and#))))
ClojureはLisp言語ファミリーの一員です。Lispの多くの特徴は他の言語にも取り入れられてきましたが、コードをデータとして扱うアプローチとマクロシステムは依然として際立っています。Clojureはコードをデータとして扱うシステムを、括弧で囲まれたリスト(S式)だけでなく、ベクトルやマップにも拡張しています。そのため、ベクトルやマップはマクロ構文で使用でき、リテラルリーダ表現を持つことができます。
Lispのデータ、そしてLispのコードはリーダによって読み込まれます。読み込みの結果は、形式によって表現されるデータ構造です。Clojureはコードを表すデータ構造をコンパイルでき、そのプロセスの一部としてマクロの呼び出しを探します。マクロを見つけると、マクロを呼び出し、形式自体を引数として渡し、マクロの戻り値をマクロ自体の代わりに使います。したがって、マクロはコードの変換を実行するためにコンパイル時に呼び出される関数です。コードはデータであるため、Clojureライブラリのすべてが変換を支援するために利用できます。したがって、マクロはLispとClojureが構文抽象化をサポートすることを可能にします。関数を使用するのと同じ理由で、つまりコードの繰り返しを排除するためにマクロを使用します。マクロは、評価を制御したり、識別子を生成したりする必要があるなど、関数では不十分な状況のために予約されるべきです。Clojureのコア構文の多くは、ユーザーが定義できるマクロと同様に、組み込みのプリミティブではなくマクロです。ここにandがあります。
(defmacro and
([] true)
([x] x)
([x & rest]
`(let [and# ~x]
(if and# (and ~@rest) and#))))
生成する形式を模倣する形式を持つマクロを簡単に定義できる構文クォート(`)の使用に注目してください。