1. ホーム
  2. collections

[解決済み] Clojure: cons (seq) vs. conj (list)

2022-12-12 17:22:34

質問

私は、以下のことを知っています。 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)

リストを使った例で conj vs. cons は異なる挙動を示すのでしょうか、それとも本当に互換性があるのでしょうか? 別の言い方をすれば、リストとseqが等価に使用できない例はあるのでしょうか?

どのように解決するのですか?

ひとつ違うのは 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

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

(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 はコレクションに項目を結合することを意味する。そのため seq によって構成される cons は、第1引数として渡された要素から始まり、その要素には next / rest を適用した結果生じたものを分ける。 seq を第二引数に適用した結果生じるものです。上に表示されているように、全体はクラス clojure.lang.Cons . これに対して conj は常に渡されたコレクションとほぼ同じ型のコレクションを返します。(大まかな理由は PersistentArrayMapPersistentHashMap に変わります)。


1 従来、Lispの世界では cons はペアを構成するので、ClojureはLispの伝統から離れ、その cons を持たないseqを構築するという点で、ClojureはLispの伝統から外れています。 cdr . の一般的な使い方は cons を使用して、いくつかの値をまとめて保持するために何らかの型のレコードを構築することを意味する、プログラミング言語とその実装の研究では現在いたるところで使用されています。