user3139545
user3139545

Reputation: 7374

Custom implementation of count for lazy seq

In the example code below I return a lazy list. What I would like to happen when someone calls count on the list is that some arbitrary function get executed instead and returns whatever I like.

(defn my-range [i limit]
  (lazy-seq 
   (when (< i limit)
     (cons i (my-range (inc i) limit)))))

(count (my-range 0 9)) returns whatever

I'm not sure if this should be possible: I have been looking at reifybut can't figure out if it can be used in this situation.

Upvotes: 4

Views: 203

Answers (1)

amalloy
amalloy

Reputation: 91857

You can do this, but it's rather a lot of work: you have to implement all the sequence-related interfaces yourself, and delegate most of them to your lazy seq. Here's a sketch:

(defn my-range [i limit]
  (let [ret (lazy-seq 
              (when (< i limit)
                (cons i (my-range (inc i) limit))))]
    (reify
      clojure.lang.Counted
      (count [this] 10)
      clojure.lang.Sequential
      clojure.lang.ISeq
      (first [this] (.first ret))
      (next [this] (.next ret))
      (more [this] (.more ret))
      (cons [this x] (.cons ret x))
      (empty [this] (.empty ret))
      (equiv [this x] (.equiv ret x))
      (seq [this] (.seq ret)))))

And indeed (my-range 1 3) returns a two-item sequence which claims to have a count of 10, which is what you wanted.

Upvotes: 4

Related Questions