Clojure:cons(seq)とconj(リスト)


98

私はそれconsがシーケンスを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)

リストを使用して、任意の例があるconj対はcons異なる挙動を示すが、または彼らは本当に互換性がありますか?別の言い方をすると、リストとシーケンスを同等に使用できない例はありますか?

回答:


150

1つの違いは、conj任意の数の引数を受け入れてコレクションに挿入することですが、cons1つしか取りません。

(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.Consは実装されていないclojure.lang.Countedため、counton onはもはや一定時間操作ではありません(この場合、おそらく1 + 3に減少します-1は最初の要素の線形トラバーサルから、3は(next (cons 4 '(1 2 3))a PersistentListとしたがってCounted)。

名前の背後にある意図は、それconsがcons(truct a seq)1conj意味するのに対し、conj(アイテムをコレクションに追加する)を意味すると私は信じています。seq構成されcons、その第一引数として渡された要素で始まり、そのよう有するnext/ rest一部のアプリケーションに起因するものseq二番目の引数に。上に表示されているように、全体がclass clojure.lang.Consです。対照的に、conj常に、渡されたコレクションとほぼ同じ型のコレクションを返します。(大まかに言うと、9エントリを超えるとすぐPersistentArrayMapにaがaに変わるからPersistentHashMapです。)


1伝統的に、Lispの世界ではconscons(truss a pair)であるため、ClojureはLispの伝統から逸脱し、そのcons機能は従来のを持たないseqを構築しcdrます。cons「いくつかのタイプのレコードを構築して多数の値をまとめて保持する」という意味の一般化された用法は、現在、プログラミング言語とその実装の研究において広く普及しています。それは「同意を避ける」が言及されているときの意味です。


1
なんて素晴らしい記事でしょう!短所タイプがあることに気づきませんでした。よくやった!
Daniel Yankowsky

ありがとう。それを聞いてうれしいです。:-)
のMichałMarczyk

2
ちなみに、特殊なケースとして、(cons foo nil)シングルトンを返しますPersistentList(同様にconj)。
のMichałMarczyk

1
別の素晴らしい説明。あなたは本当にclojure jediです!
dbyrne

1
私の経験では、パフォーマンスが重要な場合は、リストをリストではなくシーケンスとして扱うことが重要です。
cgrand

11

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

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


8

もう1つの違いはconj、シーケンスを最初の引数として取るため、をあるシーケンスalterに更新するときにうまく機能refすることです。

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

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


2

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

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

4
consは常にシーケンスを返し、conjは提供されたものと同じタイプを返します
Ning Sun

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.