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来开始