Make a Java class work as a sequence in Clojure
-
09-07-2021 - |
Pergunta
I am using a Java class that represents a sequence of results (somewhat like a Clojure vector).
I would like to use this class with the typical Clojure sequence functions (i.e. I want to have the class behave as if it supported the sequence abstraction) however I can't change the class so am unable to make it implement clojure.lang.Seqable
or similar. Also, annoyingly, the class does not implement java.util.Collection
or java.lang.Iterable
.
I can see a few options:
- Use
iterator-seq
on the object's (existing) iterator. - Wrap the object in another class that implements
java.util.Collection
/clojure.lang.Sequable
- Create a function that builds a Clojure vector or sequence by querying the Object
Are there any other options? What is the best approach?
Solução
The fastest and most straightforward would be to use iterator-seq
.
This does beg the question: Why doesn't core Clojure provide a protocol like SeqSource that would be called by seq
. Then non-standard collections could be "extended" to supply a seq, similar to how the InternalReduce works for reduce
.
Outras dicas
Use proxy
to extend the class and make it implement ISeq
My first shot would be to create lazy-seq of that object:
(defn sequify [obj]
(letfn [(inner [idx]
(when (< idx (.size obj))
(cons (.get obj idx)
(lazy-seq
(inner (inc idx))))))]
(inner 0)))
Just replace .size
and .get
with appropriate methods.
Writing a wrapper may be more appropriate if you want to improve performance compared to lazy-seq
solution.