私はJavaプログラマーであり、Clojureを初めて使用します。さまざまな場所から、シーケンスとコレクションがさまざまなケースで使用されているのを見ました。しかし、それらの正確な違いはわかりません。
いくつかの例:
1)Clojureのドキュメントで シーケンス :
_The Seq interface
(first coll)
Returns the first item in the collection.
Calls seq on its argument. If coll is nil, returns nil.
(rest coll)
Returns a sequence of the items after the first. Calls seq on its argument.
If there are no more items, returns a logical sequence for which seq returns nil.
(cons item seq)
Returns a new seq where item is the first element and seq is the rest.
_
ご覧のとおり、Seqインターフェースを説明するとき、最初の2つの関数(first/rest)はこれがコレクションであることを示すように見えるcoll
を使用し、cons
関数はこれがシーケンスであることを示すように見えるseq
を使用します。
2)値がコレクションであるかシーケンスであるかをテストするために使用できる_coll?
_および_seq?
_と呼ばれる関数があります。明らかにコレクションとシーケンスが異なります。
3) ' Collections 'に関するClojureのドキュメントでは、次のように述べられています。
コレクションはseq関数をサポートしているため、すべてのシーケンス関数を任意のコレクションで使用できます。
これは、すべてのコレクションがシーケンスであることを意味しますか?
_(coll? [1 2 3]) ; => true
(seq? [1 2 3]) ; => false
_
上記のコードは、_[1 2 3]
_がコレクションであるがシーケンスではないため、そのようなケースではないことを示しています。
これはClojureにとってかなり基本的な質問だと思いますが、これを明確に説明する場所を見つけることができません。それらの違いは何であり、さまざまなケースでどちらを使用する必要がありますか。コメントをいただければ幸いです。
すべてのシーケンスはコレクションですが、すべてのコレクションがシーケンスであるとは限りません。
seq
関数を使用すると、コレクションをシーケンスに変換できます。例えば。マップの場合、そのエントリのリストを取得します。ただし、そのエントリのリストはマップ自体とは異なります。
コアのfirst
およびrest
関数をサポートするオブジェクトはすべてsequence
です。
多くのオブジェクトがこのインターフェースを満たし、すべてのClojureコレクションは、seq
関数を使用してそのコンテンツをウォークスルーするための少なくとも1種類のseqオブジェクトを提供します。
そう:
user> (seq [1 2 3])
(1 2 3)
また、map
からシーケンスオブジェクトを作成することもできます
user> (seq {:a 1 :b 2})
([:a 1] [:b 2])
そのため、filter
map
などでfor
、maps
、sets
などを使用できます。
したがって、コレクションのような多くのオブジェクトをシーケンスとして扱うことができます。
filter
などの多くのシーケンス処理関数が入力でseq
を呼び出すのもそのためです。
(defn filter
"Returns a lazy sequence of the items in coll for which
(pred item) returns true. pred must be free of side-effects."
{:added "1.0"
:static true}
([pred coll]
(lazy-seq
(when-let [s (seq coll)]
(filter pred 5)
に電話した場合
Don't know how to create ISeq from: Java.lang.Long
RT.Java:505 clojure.lang.RT.seqFrom
RT.Java:486 clojure.lang.RT.seq
core.clj:133 clojure.core/seq
core.clj:2523 clojure.core/filter[fn]
seq
呼び出しがこのオブジェクトがシーケンス検証であることがわかります。
このようなもののほとんどは Joy of Clojure 第5章にあります。
勇敢で真のClojure で、著者はそれを本当に理解できる方法で要約します:
コレクションの抽象化は、シーケンスの抽象化と密接に関連しています。 Clojureのコアデータ構造(ベクトル、マップ、リスト、セット)はすべて、両方の抽象化に参加しています。
抽象化は、シーケンスの抽象化がメンバーを個別に操作する「約」であるのに対し、コレクションの抽象化はデータ構造全体の「約」であるという点で異なります。たとえば、コレクション関数
count
、empty?
、およびevery?
は個々の要素に関するものではありません。彼らは全体についてです。
collectionとsequenceの違いを理解するのに役立ついくつかのポイントがあります。
「コレクション」と「シーケンス」は抽象化であり、特定の値から決定できるプロパティではありません。
コレクションは価値のあるバッグです。
シーケンスは、シーケンシャル(線形)方式でアクセスされることが期待されるデータ構造(コレクションのサブセット)です。
次の図は、それらの間の関係を最もよく表しています。
あなたはそれについてもっと読むことができます ここ 。
ために - seq?
:
XがISeqを実装している場合はtrueを返します
ために - coll?
:
XがIPersistentCollectionを実装している場合はtrueを返します
そして、 ISeq interface がClojureソースコードのIPersistentCollectionから拡張されていることがわかりました。そのため、Rördが言ったように、すべてのシーケンスはコレクションです。
「TheJoyofClojure」の第5章「コレクションタイプ」を読んだばかりですが、少し紛らわしいです(つまり、その本の次のバージョンにはレビューが必要です)。 86ページの第5章には、私が完全に満足していない表があります。
これが私の見解です(1か月の反省の後でこれに戻った後に完全に更新されました)。
それは「もの」、他のもののコレクションです。
これは、関数coll?
に基づいています。
coll?
を使用して、これをテストできます。coll?
がtrueを返すものはすべてコレクションです。coll?
docstringは次のように述べています。
Xが
IPersistentCollection
を実装している場合はtrueを返します
3つの別々のクラスにグループ化されたコレクションであるもの。異なるクラスのものは決して等しくありません。
(map? foo)
[.____を使用してテストします。](sequential? (sorted-map :a 1)
; => false(set? foo)
[.____を使用してテストします。](sequential? (sorted-set :a :b))
; => false(sequential? foo)
[.____を使用してテストします。](sequential? (seq [1 2 3]))
; => true(sequential? (lazy-seq (seq [1 2 3])))
; => trueJava相互運用機能はこれ以外のものです:
(coll? (to-array [1 2 3]))
; => false(map? (doto (new Java.util.HashMap) (.put "a" 1) (.put "b" 2)))
; => falseそれは「もの」であり、他のものを保持するコレクションです特定の安定した順序に従って。
これは、関数sequential?
に基づいています。
sequential?
を使用して、これをテストできます。sequential?
がtrueを返すものはすべて、順次コレクションです。sequential?
docstringは次のように述べています。
CollがSequentialを実装している場合はtrueを返します
注:「シーケンシャル」は形容詞です。 「TheJoyof Clojure」では、形容詞が名詞として使用されていますが、これは本当に、本当に、本当に混乱しています。
「Clojureは、各コレクションのデータ型を、シーケンシャル、マップ、セットの3つの論理カテゴリまたはパーティションのいずれかに分類します。」
「シーケンシャル」の代わりに、「シーケンシャルシング」または「シーケンシャルコレクション」(上記で使用)を使用する必要があります。一方、 mathematics には、「チェーン」、「全順序集合」、「単純順序集合」、「線形順序集合」という単語がすでに存在します。 「チェーン」は素晴らしいように聞こえますが、誰もその言葉を使用していません。恥!
「JoyofClojure」にも次のように書かれています。
タイプベースの述語に注意してください!
Clojureには、定義したばかりの単語のような名前の述語がいくつか含まれています。それらは頻繁には使用されませんが、ここでの定義が示唆していることを正確に意味していない可能性があることは言及する価値があるようです。たとえば、どのオブジェクトがシーケンシャルですか? trueを返すのはシーケンシャルコレクションですが、シーケンシャルでもあるものについてはfalseを返します[より良い:「シーケンシャルコレクションと見なすことができます」]。これは、Clojureの将来のバージョンで改善される可能性のある実装の詳細によるものです[そしておそらくこれはすでに行われていますか?]
これは、物事というよりも概念です。つまり、まだ存在している場合と存在していない場合がある一連の値(つまり、順序付けられた)(つまりストリーム)です。モノがシーケンスであると言えば、それは必然的にClojureコレクションであり、シーケンシャルコレクションでさえありますか?そうだと思います。
その順次コレクションは完全に計算され、完全に利用可能である可能性があります。または、必要に応じて値を生成するのは「マシン」である可能性があります(計算によって(おそらく「純粋な」方法で)、または外部の「不純な」「耳の」ソース(キーボード、データベース)を照会することによって)
これは、関数first
、rest
、next
、cons
(およびおそらく他の?)によって処理できるもの、つまり、 プロトコルclojure.lang.ISeq
(Javaの「インターフェイスの実装を提供する」とほぼ同じ概念)に従います。つまり、システムはペアの関数実装を登録しています(事、関数名) [これが正しいことを願っています...]
これは、関数seq?
に基づいています。
seq?
を使用してこれをテストできますseq?
がtrueを返すものです。seq?
のDocstring:
XがISeqを実装している場合はtrueを返します
first
のDocstring:
コレクションの最初のアイテムを返します。その引数でseqを呼び出します。 collがnilの場合、nilを返します。
rest
のDocstring:
最初のアイテムの後に、空の可能性のあるアイテムのシーケンスを返します。その引数でseqを呼び出します。
next
のDocstring:
最初のアイテムの後のアイテムのシーケンスを返します。その引数でseqを呼び出します。これ以上アイテムがない場合は、nilを返します。
Seqでnext
を呼び出して、次の要素と新しいseqを生成します。 nil
が取得されるまで繰り返します。
Joy of Clojureこれを「コレクションをナビゲートするためのシンプルなAPI」と呼び、「seqはseqAPIを実装する任意のオブジェクトです」と言います-「API」が「もの」のアンサンブルである場合は正しいです"(特定のタイプの)およびそのことに作用する関数。それはAPIの概念の適切な変化に依存します。
空のシーケンスの特殊なケースに関する注記:
(def empty-seq (rest (seq [:x])))
(type? empty-seq) ;=> clojure.lang.PersistentList$EmptyList
(nil? empty-seq) ;=> false ... empty seq is not nil
(some? empty-seq) ;=> true ("true if x is not nil, false otherwise.")
(first empty-seq) ;=> nil ... first of empty seq is nil ("does not exist"); beware confusing this with a nil in a nonempty list!
(next empty-seq) ;=> nil ... "next" of empty seq is nil
(rest empty-seq) ;=> () ... "rest" of empty seq is the empty seq
(type (rest empty-seq)) ;=> clojure.lang.PersistentList$EmptyList
(seq? (rest empty-seq)) ;=> true
(= (rest empty-seq) empty-seq) ;=> true
(count empty-seq) ;=> 0
(empty? empty-seq) ;=> true
seq
関数seq
をそれが理にかなっているもの(通常は順次コレクション)に適用すると、そのコレクションのメンバーを表す/生成するseqが得られます。
Docstringは言う:
コレクションのseqを返します。コレクションが空の場合、nilを返します。 (seq nil)はnilを返します。 seqは、文字列、ネイティブJava配列(参照型の)およびIterableを実装するオブジェクトでも機能します。seqsは値をキャッシュするため、イテレータが繰り返し返すIterableではseqを使用しないでください。同じ可変オブジェクト。
seq
を適用した後、さまざまな実際のクラスのオブジェクトを取得できます。
clojure.lang.Cons
-(class (seq (map #(* % 2) '( 1 2 3))))
を試してくださいclojure.lang.PersistentList
clojure.lang.APersistentMap$KeySeq
clojure.lang.PersistentList$EmptyList
clojure.lang.PersistentHashMap$NodeSeq
clojure.lang.PersistentQueue$Seq
clojure.lang.PersistentVector$ChunkedSeq
シーケンスにseq
を適用すると、返されるものの実際のクラスが、渡されたものの実際のクラスと異なる場合があります。それでもシーケンスのままです。
シーケンス内の「要素」は何ですか。たとえば、マップの場合、これらは2要素のvector
のように見えるキーと値のペアです(ただし、実際のクラスは実際にはベクトルではありません)。
lazy-seq
より多くのものを怠惰に生成するものを作成します(中断されたマシン、中断されたストリーム、 サンク )
Docstringは言う:
ISeqまたはnilを返す式の本体を受け取り、seqが最初に呼び出されたときにのみ本体を呼び出し、結果をキャッシュして後続のすべてのseq呼び出しで返すSeqableオブジェクトを生成します。も参照してください-実現しましたか?」
Clojure Universeでは、「関数」と「モノ」について話すのが好きですが、Javaらしさやその他の悪さを多用する用語である「オブジェクト」については話しません。オブジェクトの言及は、基になるJavaユニバースから破片が突き出ているように感じます。
機能と物の違いは何ですか?
流動的です!あるものは純粋関数であり、あるものは純粋なものであり、あるものはその中間にあります(関数として使用でき、物の属性を持っています)
特に、Clojureでは、キーワード(モノ)を関数(マップ内の値を検索するため)と見なすコンテキスト、マップ(モノ)を関数として解釈するコンテキスト、または関数の省略形(キーを取得してそれに関連付けられた値を返す)を使用できます。マップのキー)
明らかに、関数は「 一級市民 "」のようなものです。
それはまた文脈的です!コンテキストによっては、関数がモノになるか、モノが関数になります。
オブジェクトについての厄介な言及があります...これらは、基礎となるJavaユニバースから突き出ている破片です。