名前空間付きキーワードの意味と使い方
Clojureにおいて,キーワードは多用されます.実は,キーワードには名前空間(namespace qualifier)をつけることができます.従来はそれほど重要性は高くありませんでしたが,Clojure 1.9におけるcore.specの導入により,にわかに重要性が高まりました.機能自体は以前から存在していますが,Spec Guideを読んではじめてqualifiedキーワードの登場に面食らった人も多いのではないでしょうか.
このエントリーでは,qualifiedキーワードの記法についてまとめ,次にcore.specにおける利用方法,最後にcore.spec以外での利用方法についてまとめます.
名前空間付きキーワードの記法
Clojureにおいては,一般のvarが名前空間に属するのと同様にキーワードも名前空間に属することができます.名前空間付きキーワードは, :namespace/foo
という文法で記述することができます.qualifiedキーワードは,unqualifedキーワードとは違うものとして扱われます.また,違う名前空間に属する場合は異なるキーワードとして扱われます.
user=> :my-ns/foo :my-ns/foo user=> (= :foo :my-ns/foo) ;; unqualified / qualified キーワードは互いに等価でない false user=> (= ::foo :foo) false user=> (= :my-ns2/foo :my-ns/foo) ;; 名前空間が違う場合は等価でない false
簡略化の記法として,現在の名前空間に属するキーワードは ::foo
のように書くことができます
user=> ::foo :user/foo user=> (= ::foo :user/foo) true
また,Clojure 1.9 alpha-8 から導入された省略記法として,#:
記法があります.mapのキーにキーワードが使われている場合に記述を省略できます(alphaリリースなので将来消される可能性もありますが,alpha-10の時点では残っています).
;; 1.9 alpha-10でテスト user=> #:my-ns { :key "val" } #:my-ns{:key "val"} user=> (def my-map #:my-ns{:key "val"} ;; my-mapのキーは :my-ns/key である #’user/my-map user=> (:key my-map) nil user=> (:my-ns/key my-map) "val"
core.specにおける利用法
core.specにおいては,core.spec/def
を用いてspecをキーワードとひも付けてregistryに登録します.
;; http://clojure.org/guides/spec より引用 (s/def ::date inst?)
ここではキーワードを登録のキーとして使っており,そして(おそらく)registryはグローバルに管理されているので,unqualifiedキーワードを使ってしまうと衝突の危険があります.なので,registryのキーとしてキーワードを指定する際は必ずqualifiedなキーワードを使うべきです.普通は現在の名前空間に登録するでしょうから,「Spec Guide」では一貫して::
記法を利用した qualifiedキーワードが使われています.
core.spec以外での使用法
はっきりいって,通常の record の使用の際にqualifiedキーワードを使うことはそれほど多くないでしょう.
有用なのは,ライブラリ同士or名前空間同士で意図しない衝突を避けたい場合です.[3]では,re-frameというclojurescriptフレームワークで,イベントハンドラの名前(=キーワード)が名前空間同士で衝突しないようにqualifiedキーワードを使うことが述べられています.
[2]では,Ring v0.1ではリクエストとレスポンスのmapにqualifiedキーワードが使われていたけれどもv0.2ではunqualifiedに変更されたという経緯についても触れられています.