I'd like to know if the following way of "observing" a sequence while consuming it is correct. I've read the following SO answer(s) but I'm a bit surprised in that I've read several times that the "correct" way to do so was to use laziness (and hence explicitely make your sequence lazy even if it wasn't), yet the word "lazy" isn't even mentioned once there:
How to implement the Observer Design Pattern in a pure functional way?
So basically I have a lazy sequence and I want to keep that lazy sequence 100% pure and I don't want the observer to leak anything into that lazy sequence. In my example I'm simply using (range 100000)
but any lazy sequence would do.
Then I'm using some mutability (in Clojure using an atom) doing something like this (the code is runnable, you can copy/paste as is in a REPL):
(let [a (atom (range 100000))]
(loop [i 0]
(if (= 0 (mod i 10)) (println "i: " i)) ; the observer
(if (= 100 i)
(take 1 @a)
(do (reset! a (rest @a)) (recur (inc i))))))
The point is not that I'm using a mutable atom here but that the implementation of the lazy sequence doesn't know at all that it is being observed. The observer can obviously be fancier: like actually notifying observers instead of using side-effects to print i (once again: printing i here is just an example).
Is this a "correct" way of observing while consuming a lazy sequence?
If this is not correct, how would you observe while consuming a lazy sequence in Clojure?
Alternatively, how would you do it in Haskell?