web-dev-qa-db-ja.com

Clojure:cons(seq)vs. conj(list)

consはseqを返し、conjはコレクションを返します。また、conjはコレクションの最適な末尾にアイテムを「追加」し、consは常にアイテムを先頭に「追加」することも知っています。この例は、これらの両方のポイントを示しています。

user=> (conj [1 2 3] 4) //returns a collection
[1 2 3 4]
user=> (cons 4 [1 2 3]) //returns a seq
(4 1 2 3)

ベクトル、マップ、およびセットの場合、これらの違いは理にかなっています。ただし、リストの場合は同じように見えます。

user=> (conj (list 3 2 1) 4) //returns a list
(4 3 2 1)
user=> (cons 4 (list 3 2 1)) //returns a seq
(4 3 2 1)

conjconsが異なる動作を示すリストを使用した例はありますか、それとも本当に互換性がありますか?別の言い方をすると、リストとシーケンスを同等に使用できない例はありますか?

96
dbyrne

1つの違いは、conjはコレクションに挿入するために任意の数の引数を受け入れますが、consは1つだけをとることです。

(conj '(1 2 3) 4 5 6)
; => (6 5 4 1 2 3)

(cons 4 5 6 '(1 2 3))
; => IllegalArgumentException due to wrong arity

もう1つの違いは、戻り値のクラスです。

(class (conj '(1 2 3) 4))
; => clojure.lang.PersistentList

(class (cons 4 '(1 2 3))
; => clojure.lang.Cons

これらは実際には互換性がないことに注意してください。特に、clojure.lang.Consclojure.lang.Countedを実装しないため、その上のcountは一定時間の操作ではなくなります(この場合、おそらく1 + 3に減少します-1最初の要素に対する線形トラバーサルに由来し、3は(next (cons 4 '(1 2 3))PersistentListであり、したがってCountedであることに起因します。

名前の背後にある意図は、consがcons(truct a seq)を意味すると信じている1一方、conjはconj(アイテムをコレクションに追加する)を意味します。 seqで構成されているconsは、最初の引数として渡された要素から始まり、そのnext/rest部分として、 seqを2番目の引数に。上記のように、全体はclojure.lang.Consクラスです。対照的に、conjは常に、渡されたコレクションとほぼ同じタイプのコレクションを返します。 (おおよそ、PersistentArrayMapは9エントリを超えるとすぐにPersistentHashMapに変換されるためです。)


1 従来、LISPの世界ではcons cons(ペアを構成)であるため、Clojureはcons関数が従来のcdr。 「何らかの種類のレコードを構築していくつかの値を保持する」という意味のconsの一般的な使用法は、現在、プログラミング言語とその実装の研究で広く普及しています。それが「コンシングの回避」が言及されている場合の意味です。

146
Michał Marczyk

私の理解では、あなたの言うことは真実だということです。リスト上のconjはリスト上のconsと同等です。

Conjは「どこかに挿入」操作であり、consは「先頭に挿入」操作であると考えることができます。リストでは、先頭に挿入するのが最も論理的であるため、この場合conjとconsは同等です。

9

別の違いは、conjがシーケンスを最初の引数としてとるので、alterをあるシーケンスに更新するとき、refでうまく動作することです。

(dosync (alter a-sequence-ref conj an-item))

これは基本的に(conj a-sequence-ref an-item)スレッドセーフな方法で。これはconsでは機能しません。詳細については、Stu Hallowayによる Programming Clojure の並行性に関する章を参照してください。

8
user323818

別の違いはリストの動作ですか?

(list? (conj () 1)) ;=> true
(list? (cons 1 ())) ; => false
2
FredAKA