clojure
コレクションとシーケンス
サーチ…
構文
-
'()
→()
-
'(1 2 3 4 5)
→(1 2 3 4 5)
-
'(1 foo 2 bar 3)
→(1 'foo 2 'bar 3)
-
(
list
1 2 3 4 5)
→(1 2 3 4 5)
-
(
list*
[1 2 3 4 5])
→(1 2 3 4 5)
-
[]
→[]
-
[1 2 3 4 5]
→[1 2 3 4 5]
-
(
vector
1 2 3 4 5)
→[1 2 3 4 5]
-
(
vec
'(1 2 3 4 5))
→[1 2 3 4 5]
-
{}
=>{}
-
{:keyA 1 :keyB 2}
→{:keyA 1 :keyB 2}
-
{:keyA 1, :keyB 2}
→{:keyA 1 :keyB 2}
-
(
hash-map
:keyA 1 :keyB 2)
→{:keyA 1 :keyB 2}
-
(
sorted-map
5 "five" 1 "one")
→{1 "one" 5 "five"}
(シーケンスとして使用すると、キーによってエントリがソートされます) -
#{}
→#{}
-
#{1 2 3 4 5}
→#{4 3 2 5 1}
(順不同) -
(
hash-set
1 2 3 4 5)
→#{2 5 4 1 3}
(順序なし) -
(
sorted-set
2 5 4 3 1)
→#{1 2 3 4 5}
コレクション
組み込みのClojureコレクションはすべて不変で異種であり、リテラル構文を持ち、 conj
、 count
、およびseq
関数をサポートしています。
-
conj
は、アイテムが「追加」されている既存のコレクションと同等の新しいコレクションを「定数」または対数時間で返します。正確には、これはコレクションに依存します。 -
count
はコレクション内のアイテムの数を一定時間で返します。 -
seq
は、空のコレクションの場合はnil
を返し、空でないコレクションの場合は、一連のアイテムを一定時間で返します。
リスト
リストはカッコで示されます。
()
;;=> ()
Clojureリストは単独でリンクされたリストです。新しい要素を最も効率的な場所にコレクションに「 conj
」します。リストについては、これは最初です。
(conj () :foo)
;;=> (:foo)
(conj (conj () :bar) :foo)
;;=> (:foo :bar)
他のコレクションとは異なり、空でないリストは、評価時に特別なフォーム、マクロ、関数への呼び出しとして評価されます。したがって、 (:foo)
はリストのリテラル表現であり、 :foo
は唯一の項目としてREPL内で(:foo)
評価すると、キーワードをnullary関数として呼び出すことができないため、 IllegalArgumentException
がスローされます 。
(:foo)
;; java.lang.IllegalArgumentException: Wrong number of args passed to keyword: :foo
非空のリストの評価から、Clojureのを防ぐために、次のことができquote
それを:
'(:foo)
;;=> (:foo)
'(:foo :bar)
;;=> (:foo :bar)
残念ながら、これによって要素が評価されません。
(+ 1 1)
;;=> 2
'(1 (+ 1 1) 3)
;;=> (1 (+ 1 1) 3)
このため、通常は、引数をすべて評価し、それらの結果を使ってリストを構築するvariadic関数であるlist
を使用します。
(list)
;;=> ()
(list :foo)
;;=> (:foo)
(list :foo :bar)
;;=> (:foo :bar)
(list 1 (+ 1 1) 3)
;;=> (1 2 3)
count
は一定の時間内にアイテムの数を返します。
(count ())
;;=> 0
(count (conj () :foo))
;;=> 1
(count '(:foo :bar))
;;=> 2
リストを使って何かがリストであるかどうかテストできますかlist?
述語:
(list? ())
;;=> true
(list? '(:foo :bar))
;;=> true
(list? nil)
;;=> false
(list? 42)
;;=> false
(list? :foo)
;;=> false
peek
を使ってリストの最初の要素を得ることができます:
(peek ())
;;=> nil
(peek '(:foo))
;;=> :foo
(peek '(:foo :bar))
;;=> :foo
最初の要素を使わずにpop
を使って新しいリストを得ることができます:
(pop '(:foo))
;;=> ()
(pop '(:foo :bar))
;;=> (:bar)
空のリストをpop
しようとすると、 IllegalStateException
が発生することに注意してください。
(pop ())
;; java.lang.IllegalStateException: Can't pop empty list
最後に、すべてのリストはシーケンスなので、他のシーケンスで行うことができるリストですべてを行うことができます。実際には、空のリストを除いて、リストのseq
を呼び出すと、まったく同じオブジェクトが返されます。
(seq ())
;;=> nil
(seq '(:foo))
;;=> (:foo)
(seq '(:foo :bar))
;;=> (:foo :bar)
(let [x '(:foo :bar)]
(identical? x (seq x)))
;;=> true
シーケンス
シーケンスは非常にリストに似ています。 first
要素またはrest
の要素を一定時間に渡すことができる不変オブジェクトです。あなたもできるcons
初めに固執するために、既存のシーケンスおよび項目から新しいシーケンスをtruct。
seq?
を使って何かがシーケンスかどうかテストできますかseq?
述語:
(seq? nil)
;;=> false
(seq? 42)
;;=> false
(seq? :foo)
;;=> false
ご存じのように、リストはシーケンスです:
(seq? ())
;;=> true
(seq? '(:foo :bar))
;;=> true
seq
またはrseq
または空でないコレクションのkeys
またはvals
を呼び出すことによって得られるものもシーケンスです。
(seq? (seq ()))
;;=> false
(seq? (seq '(:foo :bar)))
;;=> true
(seq? (seq []))
;;=> false
(seq? (seq [:foo :bar]))
;;=> true
(seq? (rseq []))
;;=> false
(seq? (rseq [:foo :bar]))
;;=> true
(seq? (seq {}))
;;=> false
(seq? (seq {:foo :bar :baz :qux}))
;;=> true
(seq? (keys {}))
;;=> false
(seq? (keys {:foo :bar :baz :qux}))
;;=> true
(seq? (vals {}))
;;=> false
(seq? (vals {:foo :bar :baz :qux}))
;;=> true
(seq? (seq #{}))
;;=> false
(seq? (seq #{:foo :bar}))
;;=> true
すべてのリストはシーケンスですが、すべてのシーケンスがリストではないことに注意してください。リストはpeek
とpop
をサポートし、一定時間内にcount
しcount
が、通常、シーケンスはそれらの関数のどれもサポートする必要はありません。 Clojureのスタックインターフェイスもサポートしていないシーケンスでpeek
またはpop
を呼び出すと、 ClassCastException
。
(peek (seq [:foo :bar]))
;; java.lang.ClassCastException: clojure.lang.PersistentVector$ChunkedSeq cannot be cast to clojure.lang.IPersistentStack
(pop (seq [:foo :bar]))
;; java.lang.ClassCastException: clojure.lang.PersistentVector$ChunkedSeq cannot be cast to clojure.lang.IPersistentStack
(peek (seq #{:foo :bar}))
;; java.lang.ClassCastException: clojure.lang.APersistentMap$KeySeq cannot be cast to clojure.lang.IPersistentStack
(pop (seq #{:foo :bar}))
;; java.lang.ClassCastException: clojure.lang.APersistentMap$KeySeq cannot be cast to clojure.lang.IPersistentStack
(peek (seq {:foo :bar :baz :qux}))
;; java.lang.ClassCastException: clojure.lang.PersistentArrayMap$Seq cannot be cast to clojure.lang.IPersistentStack
(pop (seq {:foo :bar :baz :qux}))
;; java.lang.ClassCastException: clojure.lang.PersistentArrayMap$Seq cannot be cast to clojure.lang.IPersistentStack
一定時間内にcount
を実装しないシーケンスでcount
を呼び出すと、エラーは発生しません。その代わりに、Clojureはシーケンスの終わりに達するまでシーケンス全体をトラバースし、それが通過した要素の数を返します。これは、一般的なシーケンスでは、 count
は線形で一定ではなく、時間であることを意味します。あなたは何かが一定時間サポートしているかどうかをテストすることができcount
使用してcounted?
述語:
(counted? '(:foo :bar))
;;=> true
(counted? (seq '(:foo :bar)))
;;=> true
(counted? [:foo :bar])
;;=> true
(counted? (seq [:foo :bar]))
;;=> true
(counted? {:foo :bar :baz :qux})
;;=> true
(counted? (seq {:foo :bar :baz :qux}))
;;=> true
(counted? #{:foo :bar})
;;=> true
(counted? (seq #{:foo :bar}))
;;=> false
上で述べたように、 first
にシーケンスの最初の要素を取得することができます。 first
は引数でseq
を呼び出すので、実際のシーケンスだけでなく、 "seqable"で使用できることに注意してください。
(first nil)
;;=> nil
(first '(:foo))
;;=> :foo
(first '(:foo :bar))
;;=> :foo
(first [:foo])
;;=> :foo
(first [:foo :bar])
;;=> :foo
(first {:foo :bar})
;;=> [:foo :bar]
(first #{:foo})
;;=> :foo
また、上記のように、 rest
を使用して、既存のシーケンスの最初の要素を除くすべてを含むシーケンスを取得することができます。 first
と同じように、引数にseq
を呼び出します。しかし、結果でseq
を呼び出すことはありません !つまり、2つよりも少ないアイテムを含むシーケンスでrest
を呼び出すと、 nil
代わりにback ()
が返されます:
(rest nil)
;;=> ()
(rest '(:foo))
;;=> ()
(rest '(:foo :bar))
;;=> (:bar)
(rest [:foo])
;;=> ()
(rest [:foo :bar])
;;=> (:bar)
(rest {:foo :bar})
;;=> ()
(rest #{:foo})
;;=> ()
シーケンス内に要素がnil
ときにnil
返すには、 rest
代わりにnext
を使うことができます:
(next nil)
;;=> nil
(next '(:foo))
;;=> nil
(next [:foo])
;;=> nil
cons
関数を使用すると、最初の引数をfirst
引数、2番目の引数をrest
として返す新しいシーケンスを作成できます。
(cons :foo nil)
;;=> (:foo)
(cons :foo (cons :bar nil))
;;=> (:foo :bar)
Clojureは、 配列を扱うための多くの関数を持つ大規模な配列ライブラリを提供します。このライブラリの重要な点は、リストだけでなく、 "seqable"で動作することです。そういうわけで、シーケンスの概念はとても有用です。 reduce
ような単一の関数がすべてのコレクションに対して完全に機能することを意味します。
(reduce + '(1 2 3))
;;=> 6
(reduce + [1 2 3])
;;=> 6
(reduce + #{1 2 3})
;;=> 6
シーケンスが有用なもう一つの理由は、 first
とrest
特定の実装を強制するものではないため、必要なときにのみ要素が実現される遅延シーケンスが可能になるということです。
シーケンスを作成する式が与えられた場合、その式をlazy-seq
マクロにラップして、シーケンスのように動作するオブジェクトを取得できますが、 seq
関数ではその式を実際に評価するだけです。これは、式の結果をキャッシュし、 first
とrest
呼び出しをキャッシュされた結果に転送するように指示します。
有限シーケンスの場合、遅延シーケンスは通常、等価なシーケンスと同じように動作します。
(seq [:foo :bar])
;;=> (:foo :bar)
(lazy-seq [:foo :bar])
;;=> (:foo :bar)
しかし、その違いは無限のシーケンスで明らかになります。
(defn eager-fibonacci [a b]
(cons a (eager-fibonacci b (+' a b))))
(defn lazy-fibonacci [a b]
(lazy-seq (cons a (lazy-fibonacci b (+' a b)))))
(take 10 (eager-fibonacci 0 1))
;; java.lang.StackOverflowError:
(take 10 (lazy-fibonacci 0 1))
;;=> (0 1 1 2 3 5 8 13 21 34)
ベクトル
ベクトルは角カッコで示されます。
[]
;;=> []
[:foo]
;;=> [:foo]
[:foo :bar]
;;=> [:foo :bar]
[1 (+ 1 1) 3]
;;=> [1 2 3]
さらに、リテラル構文を使用して、 vector
関数を使用してvector
を構築することもできます。
(vector)
;;=> []
(vector :foo)
;;=> [:foo]
(vector :foo :bar)
;;=> [:foo :bar]
(vector 1 (+ 1 1) 3)
;;=> [1 2 3]
ベクトルを使って何かがベクトルかどうかテストできますかvector?
述語:
(vector? [])
;;=> true
(vector? [:foo :bar])
;;=> true
(vector? nil)
;;=> false
(vector? 42)
;;=> false
(vector? :foo)
;;=> false
conj
は要素をベクトルの最後に追加します:
(conj [] :foo)
;;=> [:foo]
(conj (conj [] :foo) :bar)
;;=> [:foo :bar]
(conj [] :foo :bar)
;;=> [:foo :bar]
count
は一定の時間内にアイテムの数を返します。
(count [])
;;=> 0
(count (conj [] :foo))
;;=> 1
(count [:foo :bar])
;;=> 2
peek
を使ってベクトルの最後の要素を得ることができます:
(peek [])
;;=> nil
(peek [:foo])
;;=> :foo
(peek [:foo :bar])
;;=> :bar
pop
を使用して最後の要素を持たない新しいベクトルを得ることができます:
(pop [:foo])
;;=> []
(pop [:foo :bar])
;;=> [:foo]
空のベクトルをポップしようとすると、 IllegalStateException
が発生することに注意してください。
(pop [])
;; java.lang.IllegalStateException: Can't pop empty vector
リストとは異なり、ベクトルは索引付けされます。 getを使って、 "定数"時間のインデックスでベクトルの要素を得ることができget
:
(get [:foo :bar] 0)
;;=> :foo
(get [:foo :bar] 1)
;;=> :bar
(get [:foo :bar] -1)
;;=> nil
(get [:foo :bar] 2)
;;=> nil
さらに、ベクトル自体は、インデックスを取得し、そのインデックスで要素を返す関数です。
([:foo :bar] 0)
;;=> :foo
([:foo :bar] 1)
;;=> :bar
しかし、無効なインデックスを持つベクトルを呼び出すと、 nil
代わりにIndexOutOfBoundsException
が発生します。
([:foo :bar] -1)
;; java.lang.IndexOutOfBoundsException:
([:foo :bar] 2)
;; java.lang.IndexOutOfBoundsException:
assoc
を使用して、特定のインデックスに異なる値を持つ新しいベクトルを取得できます。
(assoc [:foo :bar] 0 42)
;;=> [42 :bar]
(assoc [:foo :bar] 1 42)
;;=> [:foo 42]
ベクトルのcount
に等しいインデックスを渡すと、Clojureはconj
を使用したかのように要素を追加します。しかし、負のcount
またはより大きいcount
インデックスを渡すと、 IndexOutOfBoundsException
が発生します。
(assoc [:foo :bar] 2 42)
;;=> [:foo :bar 42]
(assoc [:foo :bar] -1 42)
;; java.lang.IndexOutOfBoundsException:
(assoc [:foo :bar] 3 42)
;; java.lang.IndexOutOfBoundsException:
seq
を使用して、ベクトル内のアイテムのシーケンスを取得できます。
(seq [])
;;=> nil
(seq [:foo])
;;=> (:foo)
(seq [:foo :bar])
;;=> (:foo :bar)
ベクトルがインデックスされているので、 rseq
を使ってベクトルのアイテムの逆のシーケンスを得ることもできます:
(rseq [])
;;=> nil
(rseq [:foo])
;;=> (:foo)
(rseq [:foo :bar])
;;=> (:bar :foo)
すべてのリストはシーケンスですが、シーケンスはリストと同じ方法で表示されますが、すべてのシーケンスがリストではありません。
'(:foo :bar)
;;=> (:foo :bar)
(seq [:foo :bar])
;;=> (:foo :bar)
(list? '(:foo :bar))
;;=> true
(list? (seq [:foo :bar]))
;;=> false
(list? (rseq [:foo :bar]))
;;=> false
セット
マップと同様に、セットは連想的で順序付けられていません。キーから値へのマッピングを含むマップとは異なり、セットは基本的にキーからそれ自身にマップされます。
セットは、中括弧で区切られた8角形で表されます。
#{}
;;=> #{}
#{:foo}
;;=> #{:foo}
#{:foo :bar}
;;=> #{:bar :foo}
マップと同様に、要素がリテラルセットに現れる順序は関係ありません。
(= #{:foo :bar} #{:bar :foo})
;;=> true
セットを使用して何かがセットであるかどうかテストできますかset?
述語:
(set? #{})
;;=> true
(set? #{:foo})
;;=> true
(set? #{:foo :bar})
;;=> true
(set? nil)
;;=> false
(set? 42)
;;=> false
(set? :foo)
;;=> false
containsを使用して、マップが一定の時間内に特定のアイテムを含むかどうかをテストできcontains?
述語:
(contains? #{} :foo)
;;=> false
(contains? #{:foo} :foo)
;;=> true
(contains? #{:foo} :bar)
;;=> false
(contains? #{} nil)
;;=> false
(contains? #{nil} nil)
;;=> true
さらに、セット自体は要素を受け取り、その要素がセットに含まれている場合はそれを返す関数で、そうでない場合はnil
を返します。
(#{} :foo)
;;=> nil
(#{:foo} :foo)
;;=> :foo
(#{:foo} :bar)
;;=> nil
(#{} nil)
;;=> nil
(#{nil} nil)
;;=> nil
conj
を使用すると、既存のセットのすべての要素に加えて、1つの追加アイテムを持つセットを取得できます。
(conj #{} :foo)
;;=> #{:foo}
(conj (conj #{} :foo) :bar)
;;=> #{:bar :foo}
(conj #{:foo} :foo)
;;=> #{:foo}
disj
を使って、既存のセットのすべての要素から1つのアイテムを除いたセットを取得することができます:
(disj #{} :foo)
;;=> #{}
(disj #{:foo} :foo)
;;=> #{}
(disj #{:foo} :bar)
;;=> #{:foo}
(disj #{:foo :bar} :foo)
;;=> #{:bar}
(disj #{:foo :bar} :bar)
;;=> #{:foo}
count
は、要素の数を一定時間で返します。
(count #{})
;;=> 0
(count (conj #{} :foo))
;;=> 1
(count #{:foo :bar})
;;=> 2
seq
を使用して、セット内のすべての要素のシーケンスを取得できます。
(seq #{})
;;=> nil
(seq #{:foo})
;;=> (:foo)
(seq #{:foo :bar})
;;=> (:bar :foo)
地図
シーケンシャルなデータ構造であるリストとは異なり、シーケンシャルでも連想的でもあるベクトルは、排他的に連想データ構造です。マップは、キーから値へのマッピングのセットで構成されます。すべてのキーはユニークなので、マップはキーから値への「定数」検索をサポートします。
マップは、中括弧で示されます。
{}
;;=> {}
{:foo :bar}
;;=> {:foo :bar}
{:foo :bar :baz :qux}
;;=> {:foo :bar, :baz :qux}
2つの要素の各ペアは、キーと値のペアです。したがって、たとえば、上記の最初のマップにはマッピングがありません。 2番目のマッピングは、キー:foo
から値:bar
までの1つのマッピングを持ち:bar
。 3番目のマッピングはキーからのもの、つまり:foo
から値:bar
へのマッピングと、キー:baz
から値:qux
へのものの2 :qux
です。マップは本質的に順序付けされていないので、マッピングが現れる順序は関係ありません。
(= {:foo :bar :baz :qux}
{:baz :qux :foo :bar})
;;=> true
マップを使って何かが地図であるかどうかテストできますかmap?
述語:
(map? {})
;;=> true
(map? {:foo :bar})
;;=> true
(map? {:foo :bar :baz :qux})
;;=> true
(map? nil)
;;=> false
(map? 42)
;;=> false
(map? :foo)
;;=> false
contains?
を使用して、一定の時間内に指定されたキーがマップに含まれているかどうかをテストできcontains?
述語:
(contains? {:foo :bar :baz :qux} 42)
;;=> false
(contains? {:foo :bar :baz :qux} :foo)
;;=> true
(contains? {:foo :bar :baz :qux} :bar)
;;=> false
(contains? {:foo :bar :baz :qux} :baz)
;;=> true
(contains? {:foo :bar :baz :qux} :qux)
;;=> false
(contains? {:foo nil} :foo)
;;=> true
(contains? {:foo nil} :bar)
;;=> false
getには、キーに関連付けられた値をget
。
(get {:foo :bar :baz :qux} 42)
;;=> nil
(get {:foo :bar :baz :qux} :foo)
;;=> :bar
(get {:foo :bar :baz :qux} :bar)
;;=> nil
(get {:foo :bar :baz :qux} :baz)
;;=> :qux
(get {:foo :bar :baz :qux} :qux)
;;=> nil
(get {:foo nil} :foo)
;;=> nil
(get {:foo nil} :bar)
;;=> nil
さらに、マップ自体はキーを取得し、そのキーに関連付けられた値を返す関数です。
({:foo :bar :baz :qux} 42)
;;=> nil
({:foo :bar :baz :qux} :foo)
;;=> :bar
({:foo :bar :baz :qux} :bar)
;;=> nil
({:foo :bar :baz :qux} :baz)
;;=> :qux
({:foo :bar :baz :qux} :qux)
;;=> nil
({:foo nil} :foo)
;;=> nil
({:foo nil} :bar)
;;=> nil
find
を使用して、マップ要素全体(キーと値を一緒に)を2要素ベクトルとして取得できfind
。
(find {:foo :bar :baz :qux} 42)
;;=> nil
(find {:foo :bar :baz :qux} :foo)
;;=> [:foo :bar]
(find {:foo :bar :baz :qux} :bar)
;;=> nil
(find {:foo :bar :baz :qux} :baz)
;;=> [:baz :qux]
(find {:foo :bar :baz :qux} :qux)
;;=> nil
(find {:foo nil} :foo)
;;=> [:foo nil]
(find {:foo nil} :bar)
;;=> nil
key
またはval
を使用して、マップエントリからキーまたは値を抽出することができます。
(key (find {:foo :bar} :foo))
;;=> :foo
(val (find {:foo :bar} :foo))
;;=> :bar
すべてのClojureマップエントリはベクトルですが、すべてのベクトルがマップエントリではありません。マップエントリではないものでkey
またはval
を呼び出そうとすると、 ClassCastException
:
(key [:foo :bar])
;; java.lang.ClassCastException:
(val [:foo :bar])
;; java.lang.ClassCastException:
map-entry?
を使って何かがマップエントリであるかどうかテストできますかmap-entry?
述語:
(map-entry? (find {:foo :bar} :foo))
;;=> true
(map-entry? [:foo :bar])
;;=> false
assoc
を使用すると、1つのマッピングを追加または変更して、既存のマップと同じキーと値のペアをすべて持つマップを取得できます。
(assoc {} :foo :bar)
;;=> {:foo :bar}
(assoc (assoc {} :foo :bar) :baz :qux)
;;=> {:foo :bar, :baz :qux}
(assoc {:baz :qux} :foo :bar)
;;=> {:baz :qux, :foo :bar}
(assoc {:foo :bar :baz :qux} :foo 42)
;;=> {:foo 42, :baz :qux}
(assoc {:foo :bar :baz :qux} :baz 42)
;;=> {:foo :bar, :baz 42}
dissoc
を使用すると、既存のマップと同じキーと値のペアをすべて持つマップを取得できます。マッピングは1つdissoc
れません。
(dissoc {:foo :bar :baz :qux} 42)
;;=> {:foo :bar :baz :qux}
(dissoc {:foo :bar :baz :qux} :foo)
;;=> {:baz :qux}
(dissoc {:foo :bar :baz :qux} :bar)
;;=> {:foo :bar :baz :qux}
(dissoc {:foo :bar :baz :qux} :baz)
;;=> {:foo :bar}
(dissoc {:foo :bar :baz :qux} :qux)
;;=> {:foo :bar :baz :qux}
(dissoc {:foo nil} :foo)
;;=> {}
count
は一定の時間内にマッピングの数を返します:
(count {})
;;=> 0
(count (assoc {} :foo :bar))
;;=> 1
(count {:foo :bar :baz :qux})
;;=> 2
seq
を使用して、マップ内のすべてのエントリのシーケンスを取得できます。
(seq {})
;;=> nil
(seq {:foo :bar})
;;=> ([:foo :bar])
(seq {:foo :bar :baz :qux})
;;=> ([:foo :bar] [:baz :qux])
繰り返しますが、マップは順序付けされていないので、マップ上でseq
を呼び出すことによって得られるシーケンス内のアイテムの順序は未定義です。
あなただけのキーまたは使用してマップ内だけで値のシーケンスを取得することができkeys
やvals
、それぞれ:
(keys {})
;;=> nil
(keys {:foo :bar})
;;=> (:foo)
(keys {:foo :bar :baz :qux})
;;=> (:foo :baz)
(vals {})
;;=> nil
(vals {:foo :bar})
;;=> (:bar)
(vals {:foo :bar :baz :qux})
;;=> (:bar :qux)
Clojure 1.9では、キーが同じ名前空間を共有するマップをより簡潔に表現するためのリテラル構文が追加されています。いずれの場合もマップは同一であることに注意してください(マップはデフォルトの名前空間を「認識」しません)。これは単なる構文上の便宜です。
;; typical map syntax
(def p {:person/first"Darth" :person/last "Vader" :person/email "[email protected]"})
;; namespace map literal syntax
(def p #:person{:first "Darth" :last "Vader" :email "[email protected]"})