The simplest Lazy feature in Clojure

I find it hard to understand laziness.

Can someone help me understand why my function below is not lazy

(defn my-red ([f coll] (my-red f (first coll) (rest coll) )) ([f init coll] (let [mr (fn [gicd] (if (empty? c) d (recur g (gi (first c)) (rest c) (conj d (gi (first c)) ))))] (lazy-seq (mr f init coll []))))) 

whereas this example given in clojure.org/lazy,

 (defn filter "Returns a lazy sequence of the items in coll for which (pred item) returns true. pred must be free of side-effects." [pred coll] (let [step (fn [pc] (when-let [s (seq c)] (if (p (first s)) (cons (first s) (filter p (rest s))) (recur p (rest s)))))] (lazy-seq (step pred coll)))) 
+4
source share
3 answers

Laziness in filter comes from calling filter in the if branches of a recursive loop. That the code falls into another lazy-seq and stops evaluating seq until another element is requested.

Your my-red implementation calls lazy-seq once and only once, which means that your seq is either not evaluated at all or fully evaluated.

+8
source

The mr function will simply repeat across the entire column. Perhaps your fingerprint is misleading. correctly indented and with some useless parameters removed function looks something like this:

 (defn my-red ([f coll] (my-red f (first coll) (rest coll) )) ([f init coll] (let [mr (fn [icd] (if (empty? c) d (recur (fi (first c)) (rest c) (conj d (fi (first c))))))] (lazy-seq (mr init coll []))))) 

Basically, you wrap (lazy-seq) around a mr function that does all the work in one big recur loop.

+2
source

All lazy-seq does accepts its argument and delays its execution. To create a true lazy sequence, each link must be wrapped in a lazy call. The “granularity” of laziness is how much work is done between lazy-seq calls. The only way around this is to use higher level functions that return lazy seq.

In addition, tail recursion and laziness are mutually exclusive. This does not lead to a stack overflow, because at each step the recursive call ends in a lazy segment and returns. If the caller tries to evaluate lazy seq, a recursive call is called, but it is called by the original caller of the sequence function, not the sequence function itself, which means the stack is not growing. This is somewhat similar to the idea of ​​implementing optimized tail recursion through trampolines (see Clojure trampoline Function).

Here is a version that is lazy:

 (defn my-red ([f coll] (my-red f (first coll) (rest coll) )) ([f init coll] (let [mr (fn mr [gic] (if (empty? c) nil (let [gi (gi (first c))] (lazy-seq (cons gi (mr g gi (rest c)))))))] (lazy-seq (mr f init coll))))) 

Notice how each mr run immediately returns either nil or lazy seq, and the recursive call comes from the lazy-seq call.

+2
source

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


All Articles