web-dev-qa-db-ja.com

Clojureのシーケンスとコレクションの違いは何ですか

私は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にとってかなり基本的な質問だと思いますが、これを明確に説明する場所を見つけることができません。それらの違いは何であり、さまざまなケースでどちらを使用する必要がありますか。コメントをいただければ幸いです。

31
nybon

すべてのシーケンスはコレクションですが、すべてのコレクションがシーケンスであるとは限りません。

seq関数を使用すると、コレクションをシーケンスに変換できます。例えば。マップの場合、そのエントリのリストを取得します。ただし、そのエントリのリストはマップ自体とは異なります。

16
Rörd

コアの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])

そのため、filtermapなどでformapssetsなどを使用できます。

したがって、コレクションのような多くのオブジェクトをシーケンスとして扱うことができます。

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章にあります。

22

勇敢で真のClojure で、著者はそれを本当に理解できる方法で要約します:

コレクションの抽象化は、シーケンスの抽象化と密接に関連しています。 Clojureのコアデータ構造(ベクトル、マップ、リスト、セット)はすべて、両方の抽象化に参加しています。

抽象化は、シーケンスの抽象化がメンバーを個別に操作する「約」であるのに対し、コレクションの抽象化はデータ構造全体の「約」であるという点で異なります。たとえば、コレクション関数countempty?、およびevery?は個々の要素に関するものではありません。彼らは全体についてです。

13
Adam Arold

collectionsequenceの違いを理解するのに役立ついくつかのポイントがあります。

  1. 「コレクション」と「シーケンス」は抽象化であり、特定の値から決定できるプロパティではありません。

  2. コレクションは価値のあるバッグです。

  3. シーケンスは、シーケンシャル(線形)方式でアクセスされることが期待されるデータ構造(コレクションのサブセット)です。

次の図は、それらの間の関係を最もよく表しています。

enter image description here

あなたはそれについてもっと読むことができます ここ

10
divyum

ために - seq?

XがISeqを実装している場合はtrueを返します

ために - coll?

XがIPersistentCollectionを実装している場合はtrueを返します

そして、 ISeq interface がClojureソースコードのIPersistentCollectionから拡張されていることがわかりました。そのため、Rördが言ったように、すべてのシーケンスはコレクションです。

3
nybon

「TheJoyofClojure」の第5章「コレクションタイプ」を読んだばかりですが、少し紛らわしいです(つまり、その本の次のバージョンにはレビューが必要です)。 86ページの第5章には、私が完全に満足していない表があります。

Table 5.1 from the Joy of Clojure, 2nd ed.

これが私の見解です(1か月の反省の後でこれに戻った後に完全に更新されました)。

コレクション

それは「もの」、他のもののコレクションです。

これは、関数coll?に基づいています。

  • 関数coll?を使用して、これをテストできます。
  • 逆に、coll?がtrueを返すものはすべてコレクションです。

coll?docstringは次のように述べています。

XがIPersistentCollectionを実装している場合はtrueを返します

3つの別々のクラスにグループ化されたコレクションであるもの。異なるクラスのものは決して等しくありません。

  • Maps(map? foo) [.____を使用してテストします。]
    • マップ(動作がわずかに異なる2つの実際の実装)
    • ソートされたマップ。注:(sequential? (sorted-map :a 1); => false
  • Sets(set? foo) [.____を使用してテストします。]
    • セットする
    • ソートされたセット。注:(sequential? (sorted-set :a :b)); => false
  • シーケンシャルコレクション(sequential? foo) [.____を使用してテストします。]
    • リスト
    • ベクター
    • キュー
    • シーケンス:(sequential? (seq [1 2 3])); => true
    • Lazy-Seq:(sequential? (lazy-seq (seq [1 2 3]))); => true

Java相互運用機能はこれ以外のものです:

  • (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コレクションであり、シーケンシャルコレクションでさえありますか?そうだと思います。

その順次コレクションは完全に計算され、完全に利用可能である可能性があります。または、必要に応じて値を生成するのは「マシン」である可能性があります(計算によって(おそらく「純粋な」方法で)、または外部の「不純な」「耳の」ソース(キーボード、データベース)を照会することによって)

seq

これは、関数firstrestnextcons(およびおそらく他の?)によって処理できるもの、つまり、 プロトコルclojure.lang.ISeq(Javaの「インターフェイスの実装を提供する」とほぼ同じ概念)に従います。つまり、システムはペアの関数実装を登録しています(事、関数名) [これが正しいことを願っています...]

これは、関数seq?に基づいています。

  • 関数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ユニバースから突き出ている破片です。

プレゼンテーションの目的で、コレクションの図

Collections in Clojure

1
David Tonhofer