Java 如何使用->;(线程)宏?

Java 如何使用->;(线程)宏?,java,clojure,iterator,sequence,Java,Clojure,Iterator,Sequence,我正在尝试将词类函数的输出导入索引词函数,并使用(->)线程宏打印结果输出: (defn parts-of-speech [] (seq (. POS values))) (defn index-words [pos] (iterator-seq (. dict getIndexWordIterator pos))) (-> (parts-of-speech) index-words println) 但是索引词func返回一个迭代器seq,我不确定在这个上下文中如何迭代它,

我正在尝试将词类函数的输出导入索引词函数,并使用(->)线程宏打印结果输出:

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

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

(-> (parts-of-speech) index-words println)
但是索引词func返回一个迭代器seq,我不确定在这个上下文中如何迭代它,因为我是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))
我来自一个命令式的背景,我的目标是理解thread宏,以尝试编写更惯用的Clojure(在尝试thread宏之前,我使用多个
doseq
let
s在每个序列上循环)

从评论中可以看出,thread宏可能不是实现这一点的最惯用方法,但我仍然希望看到如何使其工作,以便填补理解上的空白

另外,
(词类)
返回四个项目的序列,如果执行
(println(count w))
而不是
(println w)
,则可以看到它打印四个序列的计数,而不是一个连续序列:

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

;= 117798
;= 11529
;= 21479
;= 4481
您将如何修改上述内容以打印一个连续的字流,而不是打印四个序列的内容


顺便说一句:上面的代码是对MIT Java WordNet库()的包装。

您实际上必须调用您的函数。此时,将函数
词类
传递到
索引词

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

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

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

注意
词类周围的括号。还请注意,您使用的互操作语法非常古老。

您实际上必须调用您的函数。此时,将函数
词类
传递到
索引词

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

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

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

注意
词类周围的括号。还要注意,您使用的互操作语法非常古老。

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

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

在Clojure中,您不需要经常创建迭代器seq对象。因为clojure可以非常方便地处理“Iterable”java对象上的迭代(请参阅)。但是,迭代器本身是不可迭代的。
要完全理解这一点,您需要了解Iterables和迭代器之间的区别,这主要是因为在Java世界中保持语义的一致性和直观性:

那么什么是“seq”?

在clojure中,有一个比java的迭代器接口更高的抽象,即ISeq。迭代器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“序列”。澄清一下——当我们在不可iterable对象上调用“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网站:

seq处理Java引用数组、Iterables和字符串。由于库的其余大部分都是基于这些函数构建的,因此在Clojure算法中使用Java对象是非常受支持的

因此,迭代器seq的目的是将迭代器对象“包装”到一个序列抽象中,该序列抽象将能够利用clojures的所有功能优势

定义迭代器seq的角色

发件人:

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

就你而言,我们可以说:

“迭代器seq函数为getIndexWordsIterator生成ISeq的实现”

最后:如何迭代序列?

考虑到上下文,这个问题需要仔细回答

迭代当然是可能的——但在clojure中并不是主要关注的问题,而且它可能不是您真正想要的。由于迭代器seq已经为我们创建了一个seq,现在我们可以使用Clojure的一个函数运算符(即,在列表理解、映射函数等中)使用该seq。这样就不需要手动迭代

例如,我们经常遍历列表以查找值。在clojure中,我们可以通过 使用过滤器功能:

user=> (filter #(= \A %) (seq "ABCD"))   
(\A)
与其过滤,不如通过对每个对象的迭代将函数应用于多个对象,并将结果存储在新集合中。同样,这不需要通过Clojure中的显式迭代来完成:

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

最后,如果确实需要手动遍历集合,则可以使用循环递归构造手动、以尾部递归方式遍历序列,每次遍历一个元素:。也可以使用标准的递归调用

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

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