TL;DR

Clojure で、変更可能な格納場所を参照するための仕組み。def で作られて名前空間に登録され、スレッドごとに束縛し直すこともできる。

なぜ必要か

Clojure の名前空間はグローバルな環境になっていて、コンパイラは自由なシンボルをすべて Var として解決しようとする。そのため、関数や定数を名前で参照するときは、名前空間に登録された Var を通すことになる。めだかのclojure.core学校 は、標準ライブラリ clojure.core にある 662 個の Var を分類して解説している。

仕組み

公式リファレンスによると、Var はルート束縛を持てる(持たなくてもよい)。ルート束縛は、自分の束縛を持たないすべてのスレッドで共有される。Var の値は、そのスレッドでの束縛があればその値、なければルート束縛の値である。

def は、名前空間に同じ名前の Var がなければ新しく作り、あれば既存の Var を使う(intern)。Var の値ではなく Var そのものを得るには、var 特殊形式か #' リーダーマクロを使う。

Var はデフォルトでは静的で、メタデータに :dynamic を付けると、binding でスレッドごとに束縛し直せる。binding で作った束縛は、ほかのスレッドからは見えない。:const を付けると、コンパイル時の定数としてコンパイラが値をインライン化できる。

例

(def ^:dynamic *x* 1)
(binding [*x* 2] *x*) ;; => 2
#'*x*                 ;; Var そのもの

Var のメタデータには、docstring を入れる :doc や、引数の形を入れる :arglists がある。

注意点

Clojure Brain Teasers によると、Var は常に Java のオブジェクトを保持するので、数値を入れるとボクシングされた値になる。プリミティブのまま扱いたいリテラルには :const true を付ける。

関連

出典