Find the elements of a LazySeq that have been realized

clojure, lazy-sequences

Solution

Code:

This returns the previously realized initial fragment of the input seq as a vector:

(defn take-realized [xs]
  (letfn [(lazy-seq? [xs]
            (instance? clojure.lang.LazySeq xs))]
    (loop [xs  xs
           out []]
      (if (or (and (lazy-seq? xs) (not (realized? xs)))
              (and (not (lazy-seq? xs)) (empty? xs)))
        out
        (recur (rest xs) (conj out (first xs)))))))

Testing at the REPL:

(defn lazy-printer [n]
  (lazy-seq
   (when-not (zero? n)
     (println n)
     (cons n (lazy-printer (dec n))))))

(take-realized (lazy-printer 10))
;= []

(take-realized (let [xs (lazy-printer 10)] (dorun (take 1 xs)) xs))
;=> 10
;= [10]

;; range returns a lazy seq...
(take-realized (range 20))
;= []

;; ...wrapping a chunked seq
(take-realized (seq (range 40)))
;= [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
;   17 18 19 20 21 22 23 24 25 26 27 28 29 30 31]

;; NB. *each* chunk of range gets its own LazySeq wrapper,
;; so that it is possible to work with infinite (or simply huge) ranges

(Using `;=>` to indicate a printout.)

Discussion:

`realized?` is indeed the way to go, as suggested by Nathan. However, as I explained in my comments on Nathan's answer, one must also make sure that one doesn't inadvertently call `seq` on the one's input, as that would cause the previously-unrealized fragments of the input seq to become realized. That means that functions such as `non-empty` and `empty?` are out, since they are implemented in terms of `seq`.

(In fact, it is fundamentally impossible to tell whether a lazy seq is empty without realizing it.)

Also, while functions like `lazify` are useful for unchunking sequences, they do not prevent their underlying seqs from being realized in a chunked fashion; rather, they enable layers of processing (`map`, `filter` etc.) to operate in an unchunked fashion even while their original input seqs are chunked. There is in fact no connection at all between such "lazified" / "unchunked" seq being realized and its underlying, possibly chunked seq being realized. (In fact there is no way to establish such a connection in the presence of other observers of the input seq; absent other observers, it could be accomplished, but only at the cost of making `lazify` considerably more tedious to write.)

Problem

I have a LazySeq of connections that are created when realized. If an exception occurs while attempting to create a connection, I'd like to iterate through all of the connections that have already been realized in the LazySeq and close them. Something like: ``` (try (dorun connections) (catch ConnectException (close-connections connections))) ``` This doesn't quite work though since `close-connections` will attempt to realize the connections again. I only want to close connections that have been realized, not realize additional connections. Any ideas for doing this?

Original source