1

品詞関数の出力を索引語関数にパイプし、(->) スレッド マクロを使用して結果の出力を出力しようとしています。

(defn parts-of-speech []
  (seq (. POS values)))

(defn index-words [pos]
  (iterator-seq (. dict getIndexWordIterator pos)))

(-> (parts-of-speech) index-words println)

しかし、インデックス ワード func は iterator-seq を返します。私は Clojure を初めて使用するため、このコンテキストでそれを反復する方法がわかりません。

編集: 提案ごとにコードを更新しました。

アップデート:

@kotarak と @jayunit100 からの回答と、@sw1nn と @marko-topolnik からのコメントのおかげで、少なくとも 2 つのバリエーションが動作します。

(->> (parts-of-speech) (map index-words) (map println) doall)

(doseq [w (map index-words (parts-of-speech))]
  (println w))

私は命令的な背景から来ており、この質問での私の目標は、より慣用的な Clojure を記述しようとしてスレッド マクロを理解することです (スレッド マクロを試す前に、複数のdoseqandを使用して各シーケンスをループしていましたlet)。

コメントから、スレッド マクロはこれを行うための最も慣用的な方法ではないように見えますが、理解のギャップを埋めることができるように、それを機能させる方法を知りたいと思っています。

また、(parts-of-speech)は 4 つの項目のシーケンスを返します。 の(println (count w))代わりに を実行する(println w)と、1 つの連続したシーケンスではなく、4 つのシーケンスのカウントが出力されることがわかります。

(doseq [w (map index-words (parts-of-speech))]
  (println (count w)))

;= 117798
;= 11529
;= 21479
;= 4481

4 つのシーケンスの内容を出力する代わりに、1 つの連続した単語の流れを出力するには、上記をどのように変更しますか?

ところで: 上記のコードは MIT Java WordNet ライブラリ ( http://projects.csail.mit.edu/jwi/ ) をラップしています。

4

2 に答える 2

6

seqsとiterator-seqの関係は次のとおりです。iterator-seqはイテレータからseqを作成します。

ここで冗長性を許しますが、「iterator-seqの出力を反復処理する方法」の質問に答えるには、最初にiterator-seqを呼び出す必要がある理由を最初に明確に定義する必要があります。

Clojureでは、iterator-seqオブジェクトを頻繁に作成する必要はありません。clojureは「Iterable」Javaオブジェクトの反復を非常に手軽に処理できるため(http://clojuredocs.org/clojure_core/clojure.core/iterator-seqを参照)。ただし、イテレータ自体は反復可能ではありません。
これを完全に理解するには、IterablesとIteratorsの違いを理解する必要があります。これは主に、Javaの世界でセマンティクスの一貫性と単純さを維持するためです。JavaのIteratorがIterableではないのはなぜですか。

では、「seq」とは何ですか?

clojureには、ISeqのIteratorインターフェースであるjavaのIteratorインターフェースよりも高度な抽象化があります。iterator-seqは、内部でISeqを作成します。このISeqオブジェクトは、アイテムのシーケンシャルリストに対して動作する多くのClojure関数で使用できるようになりました。

user=> (iterator-seq (.iterator (new java.util.ArrayList ["A" "B"])))
("A" "B")
;Thus, we now have an ISeq implementation derived from an iterator.  

したがって、「iterator-seq」関数は、JavaイテレータからのClojure「シーケンス」を作成しています。明確にするために-反復不可能なオブジェクトで「iterator-seq」を呼び出すときのエラーメッセージは有益です:

user=> (iterator-seq "ASDF")                                         
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Iterator (NO_SOURCE_FILE:0)

これは、「iterator-seq」関数が入力としてjava.util.Iteratorを必要とすることを示しています。

あなたが持っているかもしれない次の論理的な質問は:

イテレータからシーケンスを作成する必要があるのはなぜですか?seq抽象化は、javaのイテレータ抽象化とどのように異なりますか?

Iterableインターフェースは、ClojureのISeqほど抽象的ではありません。たとえば、文字列について考えてみます。明らかに、文字列はシーケンシャルです。ただし、Javaでは反復できません。同じことがアレイにも当てはまります。

clojureのWebサイトから:

「seqはJava参照配列、Iterables、およびStringsで機能します。ライブラリの残りの多くはこれらの関数に基づいて構築されているため、ClojureアルゴリズムでJavaオブジェクトを使用するための優れたサポートがあります。」

したがって、iterator-seqの目的は、イテレータオブジェクトをシーケンス抽象化に「ラップ」することです。これにより、すべてのclojures機能機能を活用できるようになります。

iterator-seqの役割の定義

http://clojure.org/sequencesから:

「seq関数は、コレクションに適したISeqの実装を生成します。」

あなたの場合、私たちはそれを言うことができます:

「iterator-seq関数は、getIndexWordsIteratorのISeqの実装を生成します」。

最後に:どうすればseqを繰り返すことができますか?

文脈を考えると、この質問には注意深く答える必要があります。

反復は確かに可能ですが、clojureの主な関心事ではなく、実際にはあなたが求めているものではないかもしれません。iterator-seqはすでにSEQを作成しているので、Clojureの関数演算子(リスト内包表記、マップ関数など)の1つを使用してそのseqを使用できるようになりました。これにより、手動で繰り返す必要がなくなります。

たとえば、多くの場合、リストを反復処理して値を見つけます。clojureでは、フィルター関数を使用して値を見つけることができます。

user=> (filter #(= \A %) (seq "ABCD"))   
(\A)

フィルタリングするのではなく、各オブジェクトを反復処理して関数を複数のオブジェクトに適用し、結果を新しいコレクションに保存したい場合があります。繰り返しますが、これは必要です-Clojureでの明示的な反復を介して行う必要はありません:

user=> (map #(.hashCode %) (seq "ABCZ")) 
(65 66 67 90)

最後に、コレクションを手動で繰り返す必要がある場合は、Loop-recur構文を使用して、シーケンスを手動で末尾再帰的にトラバースできます。一度に1つの要素:http://clojure.org/functional_programming#Functional%20Programming --Recursive%20Looping。または、標準の再帰呼び出しを使用できます。

于 2012-04-23T07:25:31.580 に答える
2

実際に関数を呼び出す必要があります。現時点では、関数 parts-of-speechを に渡しindex-wordsます。

(defn parts-of-speech
  []
  (.values POS))

(defn index-words
  [pos]
  (iterator-seq (.getIndexWordIterator dict pos)))

(-> (parts-of-speech) index-words println)

を囲む括弧に注意してくださいparts-of-speech。また、使用する相互運用構文はかなり古いものであることに注意してください。

于 2012-04-23T05:51:44.870 に答える