让一个Java类在Clojure中作为序列使用

8
我正在使用一个Java类来表示一系列结果(有点像Clojure向量)。
我想要将这个类与典型的Clojure序列函数一起使用(即希望该类表现得像支持序列抽象一样),但是我不能更改该类,因此无法使其实现clojure.lang.Seqable或类似接口。而且,令人恼火的是,该类也没有实现java.util.Collectionjava.lang.Iterable接口。
我的几个选择:
  • 在对象的(现有)迭代器上使用iterator-seq
  • 将对象包装在另一个实现了java.util.Collection/clojure.lang.Sequable接口的类中
  • 创建一个函数,通过查询该对象来建立Clojure向量或序列。
还有其他选项吗?最佳方法是什么?

1
“iterator-seq” 看起来很好,内部执行的操作与您关于包装对象的第二点相同。 - Ankur
3个回答

6
最快且最直接的方法是使用iterator-seq
这确实引出了一个问题:为什么核心Clojure不提供一个像SeqSource这样的协议,可以被seq调用。然后,非标准的集合就可以"扩展"以提供一个序列,类似于InternalReduce对reduce的作用。

7
因为seq被编译器使用,所以需要Java友好(即一个接口),同时也非常频繁地被调用,因此需要尽可能快 - 协议速度比许多东西都要快,但不如简单的接口分派快。 - amalloy
@amalloy 可以考虑使用 to-seq 函数。 - M Smith
另外,令人恼火的是,该类未实现java.util.Collection或java.lang.Iterable。 - noahlz
@noahz 但是,从原始问题来看,“对象的(现有的)迭代器”意味着有一个可用的迭代器。鉴于这一点,创建代理似乎过于复杂。如果没有迭代器,那么当然可以使用其他方法。 - M Smith
添加一个名为 to-seq 的函数来执行与 seq 相同的操作根本解决不了任何问题。它仍然需要对编译器可访问,而当然没有任何 Clojure 函数可以做到这一点。 - amalloy
@amalloy - 我本应该说的是一个协议 SeqSource,它有一个函数 to-seq,可以在任何任意类上实现,从而允许任何类参与 seq 范式。 - M Smith

6
使用proxy继承类并使其实现ISeq,详见此处

2

我的第一步是创建该对象的lazy-seq:

(defn sequify [obj]
  (letfn [(inner [idx] 
                 (when (< idx (.size obj))
                          (cons (.get obj idx)
                                (lazy-seq 
                                  (inner (inc idx))))))]
    (inner 0)))

只需使用适当的方法替换.size.get即可。

如果您想提高性能,编写包装器可能比使用lazy-seq方案更合适。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接