2

I work with the Java API of Clojure and I have a persistent vector which was created through the code:

 IPersistentVector vec = PersistentVector.create();

and later populated with values.

I need to extract the contents of this vector as a LazySeq. I understand that the vector's method seq() returns an ISeq. Is there a way to convert this ISeq into a LazySeq?

Thank you,

Chris

user881285
  • 55
  • 1
  • 2
    Can you expand a little bit on *why* you need a LazySeq instance? Clojure's sequence library is designed so that you don't have to know anything about the underlying data structure. – Alex Feb 03 '14 at 18:06

2 Answers2

2

ISeq is an interface for seqs, so LazySeq implements ISeq as well. The seq function type hints its return as an ISeq.

Calling seq on a vector will return a PersistentVector$ChunkedSeq, which is a different kind of lazy sequence. It's realization is chunked to amortize the cost of producing it element-by-element (I think it evaluates 8 elements at a time iirc).

If you really want a LazySeq specifically, you could do

(lazy-cat [1 2 3])

but that would only be useful to force element-by-element evaluation and eliminate the chunking behavior.

In Java, this would be:

// once
Var lazyCat = RT.var("clojure.core", "lazy-cat");

// at use
IPersistentVector vector = ...
ISeq lv = (ISeq) lazyCat.invoke(vector);

Note that it would give me the tinglies to actually cast the result to LazySeq so I used the interface ISeq anyways here. There is no guarantee that the concrete class LazySeq is what you'll actually receive at any point in the future. Given that, you're just as well off calling seq directly:

// once
Var seq = RT.var("clojure.core", "seq");

// at use
IPersistentVector vector = ...
ISeq lv = (ISeq) seq.invoke(vector);

In general, it is a good idea to always invoke Clojure classes through Vars obtained from the runtime and to only cast to interfaces, never to concrete types. That greatly reduces the chances that things will break for you from release to release.

Alex Miller
  • 69,183
  • 25
  • 122
  • 167
  • lazy-cat is a macro, so this wouldn't work. But since, as you say, the whole thing's a bad idea anyway, that's not such a loss. – amalloy Feb 03 '14 at 21:44
1

I can think of absolutely no good reason to do this and several bad ones, but here's the lower level.

import clojure.lang.*;

public class Foo {
    public static IFn thunk(final Object x){
           return new AFn(){
               public Object invoke() { return x; } 
           }; 
    }

     public static void main(String[] args) throws Exception {
         PersistentVector vec;
         LazySeq lazySeq;

         vec = PersistentVector.create(1, 2, 3);
         System.out.println(vec);

         lazySeq = new LazySeq(thunk(vec));
         System.out.println(lazySeq);
         System.out.println(RT.printString(lazySeq));
     }
}

Outputs, e.g.

[1 2 3]
clojure.lang.LazySeq@7861
(1 2 3)
A. Webb
  • 26,227
  • 1
  • 63
  • 95