質問

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?

役に立ちましたか?

解決

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.

他のヒント

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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top