How to monitor progress by consuming a lazy sequence?

I would like to know if the following sequence of “observing” the sequence is correctly executed when using it. I read the following SO answers, but I'm a little surprised that I read several times that the “right” way to do this is to use laziness (and therefore explicitly make your sequence lazy even if it wasn’t), but the word “lazy” not even mentioned there:

How to implement Observer design pattern in purely functional mode?

So basically I have a lazy sequence, and I want to keep this lazy sequence 100% clean, and I don’t want the observer to pass something into this lazy sequence. In my example, I just use (range 100000), but any lazy sequence will do.

Then I use some variability (in Clojure using an atom), doing something like this (the code runs, you can copy / paste, as is done in 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))))))

It is not that I use a mutable atom here, but that the implementation of a lazy sequence does not know at all that it is being observed. An observer can obviously be more fun: for example, actually notifying observers instead of using side effects to print me (again: printing here, I'm just an example).

"" ?

, Clojure?

, Haskell?

+4
2

, , , Clojure, - .

(defn lazy-report
  "Wrap s in a lazy sequence that will call f, presumably for side effects, 
   on every nth element of s during consumption."
  [s f n] 
  (let [g (cons (comp first (juxt identity f)) (repeat (dec n) identity))]
    (map #(% %2) (rest (cycle g)) s)))

(println "sum:" (reduce + (lazy-report (range 1 1000) #(println "at:" %) 100)))
;=> at: 100
;   at: 200
; ...
;   at: 900
;   sum: 499500
+4

Haskell. , , - , . .

data Stream a
    = Done 
    | Skip    (Stream a)
    | Yield a (Stream a) 

A Stream Yield , , Skip , Done, , .

a Stream, , , Yield, Stream.

eval :: Monad m => Stream (m a) -> m ()
eval Done         = return ()
eval (Yield ma s) = ma >> eval s
eval (Skip     s) = eval s

Stream ( ) "", , .

observe :: Monad m => (a -> Maybe (m b)) -> [a] -> m ()
observe f = eval . go
    where go []     = Done
          go (x:xs) = case f x of
              Nothing -> Skip     (go xs)
              Just mb -> Yield mb (go xs)

( ), observe Foldable :

observe :: (Foldable f, Monad m) => (a -> Maybe (m b)) -> f a -> m ()
observe f = eval . foldr (maybe Skip Yield . f) Done

,

f :: Int -> Maybe (IO ())
f x | x `rem` 10 == 0 = Just (print x)
    | otherwise       = Nothing

main = observe f [0..100]

.

+3

Source: https://habr.com/ru/post/1547321/


All Articles