gpt4 book ai didi

java - 如何使用 -> (thread) 宏来传递 Clojure iterator-seq?

转载 作者:行者123 更新时间:2023-11-29 10:19:02 25 4
gpt4 key购买 nike

我正在尝试将词性函数的输出通过管道传输到索引词函数中,并使用 (->) 线程宏打印结果输出:

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

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

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

但是索引词函数返回一个迭代器序列,我不确定如何在这种情况下迭代它,因为我是 Clojure 的新手。

编辑:根据建议更新代码。

更新:

感谢@kotarak 和@jayunit100 的回答以及@sw1nn 和@marko-topolnik 的评论,我至少有两个变体可以工作:

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

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

我来自命令式背景,我的这个问题的目标是理解线程宏,以尝试编写更惯用的 Clojure(在尝试线程宏之前,我使用多个 doseqlet 秒)。

从评论来看,线程宏似乎不是执行此操作的最惯用的方法,但我仍然想看看如何让它工作,以便填补理解上的空白。

此外,(parts-of-speech) 返回一个包含四个项目的序列,如果您执行 (println (count w)) 而不是 (println w) ,您可以看到它打印四个序列的计数而不是一个连续序列:

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

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

您将如何修改上面的内容以打印一个连续的单词流而不是打印四个序列的内容?

顺便说一句:上面的代码包装了 MIT Java WordNet 库 ( http://projects.csail.mit.edu/jwi/ )。

最佳答案

seqs 和 iterator-seq 之间的关系如下:一个 iterator-seq 从一个迭代器创建一个 seq。

请原谅这里的冗长,但要回答“如何迭代 iterator-seq 的输出”这个问题,我们必须首先明确定义为什么需要调用 iterator-seq 开始:

在 Clojure 中,您不会发现自己需要太频繁地创建 iterator-seq 对象。由于 clojure 可以非常方便地处理“可迭代”Java 对象的迭代(参见:http://clojuredocs.org/clojure_core/clojure.core/iterator-seq)。然而,迭代器本身是不可迭代的。
要完全理解这一点,您需要了解 Iterables 和 Iterators 之间的区别,这主要是由于在 Java 世界中保持语义一致和直接:Why is Java's Iterator not an Iterable? .

那么什么是“seq”?

在clojure中有一个比java的Iterator接口(interface)更高的抽象,就是ISeq。 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 接口(interface)不像 Clojure 的 ISeq 那样抽象。例如,考虑字符串。显然,字符串是连续的。然而,它们在 Java 中不可迭代。数组也是如此。

来自 clojure 网站:

“seq 适用于 Java 引用数组、Iterables 和字符串。由于库的其余大部分都是基于这些函数构建的,因此在 Clojure 算法中使用 Java 对象得到了很好的支持。”

因此,您的 iterator-seq 的目的是将您的迭代器对象“包装”到一个序列抽象中,这将能够利用所有 clojures 功能好东西。

定义iterator-seq的作用

来自 http://clojure.org/sequences :

“seq 函数产生适合集合的 ISeq 实现。”

在您的情况下,我们可以这样说:

“iterator-seq 函数为您的 getIndexWordsIterator 生成 ISeq 的实现”。

最后:如何迭代序列?

这个问题需要根据上下文仔细回答。

迭代当然是可能的 - 但不是 clojure 中的主要关注点,它可能不是您真正想要的。由于 iterator-seq 已经为我们创建了一个 SEQ,现在我们可以使用 Clojure 的函数运算符之一(即在列表理解、映射函数等中)来使用该 seq。这避免了手动迭代的需要。

例如,我们经常遍历列表以查找值。在 Clojure 中,我们可以通过以下方式找到一个值使用过滤功能:

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

不是过滤,我们可能希望通过遍历每个对象将函数应用于多个对象,并将结果存储在新集合中。同样,这不需要通过 Clojure 中的显式迭代来完成:

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

最后,如果你真的需要手动遍历你的集合,你可以使用 Loop-recur 构造来手动,尾递归地遍历你的序列,一次一个元素:http://clojure.org/functional_programming#Functional%20Programming--Recursive%20Looping .或者您可以使用标准递归调用。

关于java - 如何使用 -> (thread) 宏来传递 Clojure iterator-seq?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10275321/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com