如何将类似Java Iterator的对象转换为Clojure序列

How do turn a java Iterator-like object into a clojure sequence

我正在使用Sesame库在内存中的三元存储上运行SPARQL查询。

我正在使用Clojure实现此目的。

查询结果是自定义迭代器-like [1]对象,因此clojure seq不能立即使用。

将自定义java Iterator这样的对象转换为clojure序列的最优雅方法是什么?

我想到的最明显,最愚蠢的想法是遍历它并建立clojure向量,但是我敢肯定有解决这个问题的更优雅的方法。

[1] http://www.openrdf.org/doc/sesame2/api/info/aduna/iteration/Iteration.html


经过测试的版本:

1
2
3
4
5
6
7
8
(defn iteration->seq [iteration]
 (seq
  (reify java.lang.Iterable
      (iterator [this]
         (reify java.util.Iterator
           (hasNext [this] (.hasNext iteration))
           (next [this] (.next iteration))
           (remove [this] (.remove iteration)))))))


如何将类似迭代器的对象包装在实际实现Iterator接口的对象中?如下所示(未经测试):

1
2
3
4
5
6
(defn iteration-seq [iteration]
  (iterator-seq
   (reify java.util.Iterator
     (hasNext [this] (.hasNext iteration))
     (next [this] (.next iteration))
     (remove [this] (.remove iteration)))))

据我所知,Iteration接口相对于标准Iterator接口的唯一优势(如果您要称呼它)

[更新:已更正的代码使用iterator-seq代替seq,如@amalloy在对另一个答案的评论中建议的那样,它是允许声明经过检查的异常,无论如何都不会在Clojure中使用。 。]


为什么不尝试clojure.core / iterator-seq?

1
2
3
4
5
6
user=> (doc iterator-seq)
-------------------------
clojure.core/iterator-seq
([iter])
  Returns a seq on a java.util.Iterator. Note that most collections
  providing iterators implement Iterable and thus support seq directly.

如您在上面的文档字符串中所见,您甚至可能不需要显式使用iterator-seq。您是否只是尝试将Java迭代器视为REPL中的序列?


用于Java Iterable和Iterator的纯功能性可迭代到延迟序列代码

1
2
3
4
5
6
7
(defn iter-seq
  ([iterable]
    (iter-seq iterable (.iterator iterable)))
  ([iterable i]
    (lazy-seq
      (when (.hasNext i)
        (cons (.next i) (iter-seq iterable i))))))

对于自定义迭代器,请替换.iterator,.hasNext和.next调用。

的优点是它纯粹是功能性的,因为它将可迭代作为参数。其他发布的解决方案采用可变的迭代器参数,因此该函数可能会根据内部迭代器状态(违反引用透明性)而返回不同的序列。该功能还很懒惰。