0

contains?私は clojure の初心者であり、さまざまなデータ構造へのフォームの使用に少し混乱しています。

ベクトル、セット、またはマップに適用containsした結果は、私が期待したとおりです。コレクションにキー (またはインデックス) が存在するかどうかをテストします。しかし、次のようなリストになると


(def li '(1 2 3)) ; define a list
(contains? li 1) ; returns false !!??

contains?そのドキュメントには、実装が定数またはログ時間で動作すると記載されているため、リストがどのように機能するかを理解するのはそれほど簡単ではないことはわかっています。したがって、ここでは、1 がリストまたはそのインデックス範囲内にあるかどうかをログ時間未満でテストすることはあまり意味がありません。assocしかし、その場合、リストを適用するときのように例外が発生しないのはなぜですか。assoc哲学が同じである場合、assoc要素の十分に高速なランダムアクセスをサポートしていないため、リストに適用しないでください。

clojure の多くのフォームは結果として一般的なコレクションを返すので不便に感じます(vals a-map).同じことのさまざまな言い方。


(def a-map {:one 1 :two 2})
(contains? (vals a-map) 1) ; returns false!!
(contains? (set (vals a-map)) 1); returns true!!

長い説明の後、私の質問は、この設計の背後にある合理的な理由は何ですか? 要素が clojure のマップの値セットに含まれているかどうかをテストしたい場合、それをネイティブにどのように言えばよいでしょうか。つまり、もっと重要なことに、実際にばかげたバグを作らないようにするにはどうすればよいのでしょうか? ありがとう!

4

2 に答える 2

4

ソース コードを見ると、バージョン 1.4 までのclojure ではcontains?リストに対して常に false が返されることがわかります (713 行目まで落ちます)。

最新の1.5 ベータ版では、例外がスローされます。

于 2013-01-12T10:30:12.120 に答える
1

contains?キー付きコレクションでの使用のみを目的としています(たとえば、任意のキー/値ペアのマップ、整数インデックスを持つインデックス付きコレクションのベクトル)。docstringを参照してください:

clojure.core/contains?
([coll key])
  Returns true if key is present in the given collection, otherwise
  returns false.  Note that for numerically indexed collections like
  vectors and Java arrays, this tests if the numeric key is within the
  range of indexes. 'contains?' operates constant or logarithmic time;
  it will not perform a linear search for a value.  See also 'some'.

個人的には、名前が悪いので、呼ばれるべきだったと思いますhas-key?。しかし、それは過去の歴史です-誰かが(つまり、RichがAPIに重大な変更を加えることを決定しない限り)私たちはそれに固執しています。

ただし、おそらくcontains?問題が発生した場合は、アルゴリズムの観点から何か間違ったことをしている可能性があります。値を見つけるためにコレクションを順次検索するのではなく、代わりにマップまたはセットを使用する必要があります。

しかし、質問に答えるには、私はあなたに同意します。リストのようなキー付きルックアップをサポートしないものに適用された場合、containsが例外をスローする方が理にかなっています。この動作は未定義であるため、docstringと矛盾しないので、パッチを適用する価値があるのではないでしょうか。

編集:@ivantの回答から、最新の1.5ベータ版はリストに例外をスローすることがわかります。問題はすでに解決しました!

于 2013-01-12T10:35:23.627 に答える