Clojure

マクロ

目次

Clojureは、ユーザーコードによってコンパイラを拡張できる、プログラム的なマクロシステムを備えています。マクロを使用すると、他の言語ではプリミティブまたは組み込みサポートが必要となる構文構造を定義できます。Clojureの多くのコア構造は、実際にはプリミティブではなく、通常のマクロです。

一部のマクロは、プリミティブフォームの単純な組み合わせを生成します。たとえば、whenifdo を組み合わせたものです。

user=> (macroexpand '(when (pos? a) (println "positive") (/ b a)))
(if (pos? a) (do (println "positive") (/ b a)))

他のマクロは、-> マクロのように、各式を次の式の最初の引数として再帰的に挿入するなど、便利な方法でフォームを再配置します。

user=> (-> {} (assoc :a 1) (assoc :b 2))
{:b 2, :a 1}
user=> (macroexpand '(-> {} (assoc :a 1) (assoc :b 2)))
(assoc (assoc {} :a 1) :b 2)

特殊変数

より高度な使用方法のために、defmacro 内で 2 つの特殊変数を使用できます。

  • &form - 呼び出されている実際のフォーム(データとして)

  • &env - マクロ展開時点でのローカルバインディングのマップ。 env マップは、シンボルから、そのバインディングに関するコンパイラ情報を保持するオブジェクトへのマップです。

以下のマクロはすべてAPIページに記載されています。多くは、注記されているトピックページでも説明されています。

マクロの作成: defmacro definline macroexpand-1 macroexpand
分岐: and or when when-not when-let when-first if-not if-let cond condp
ループ(シーケンスも参照): for doseq dotimes while
変数の操作(変数と環境も参照): ns declare defn defmacro definline defmethod defmulti defn- defonce defstruct
コードの異なる配置: .. doto ->
動的スコープ(変数と環境も参照): binding locking time with-in-str with-local-vars with-open with-out-str with-precision
遅延評価のものの作成(シーケンスも参照): lazy-seq lazy-cat delay
Java相互運用マクロ: .. amap areduce gen-class gen-interface proxy proxy-super memfn
コードのドキュメント化: assert comment doc
トランザクション: dosync io!

いくつかの特殊フォームは、主にデストラクチャリングを提供するために、実際にはマクロとして実装されています: fn let loop