Using q / dose with infinite sequences

in Clojure, you can iterate over a sequence using the for function or similarly with doseq for side effects and get zero as the return value:

 (doseq [x (range 3)] (prn x)) ; 0 ; 1 ; 2 

for the case when the sequence is infinite, there is a way to introduce a break condition:

 (doseq [x (range) :while (< x 3)] (prn x)) 

This will lead to the same conclusion as above.

As a specialty, there is a very interesting behavior when you use more than one sequence. As the documentation calls it: "Collections repeat in nested order, most quickly faster."

 (doseq [x (range 3) y (range 3)] (prn xy)) ; 0 0 ; 0 1 ; 0 2 ; 1 0 ; 1 1 ; 1 2 ; 2 0 ; 2 1 ; 2 2 

What happens if the sequences are endless again. When the latter is infinite, it works very well. this will work equally as an example until:

 (doseq [x (range 3) y (range) :while (< y 3)] (prn xy)) 

If the first one is infinite, the resulting output will be as expected, but for some reason the loop does not stop after printing the last line. In other words: repl continues to work.

 (doseq [x (range) y (range 3) :while (< x 3)] (prn xy)) 

Can anyone explain this behavior?

+6
source share
2 answers

It does not make sense:

 (doseq [x (range) y (range 3) :while (< x 3)] (prn xy)) 

It should be:

 (doseq [x (range) :while (< x 3) y (range 3)] (prn xy)) 

... which ends.

Think of it this way:

 (doseq [x (range)] (doseq [y (range 3) :while (< x 3)] (prn xy))) 

vs

 (doseq [x (range) :while (< x 3)] (doseq [y (range 3)] (prn xy))) 

In the original version, the outer loop is infinite, because :while in inner loops doesn't matter. The cycle continues, it just does nothing. In the fixed version :while , the outer :while ends.

+13
source

Given the excellent explanation of Muhuk, it seems like a good argument in favor of explicit and not excessive code compression. So maybe like this:

 (doseq [x (range 3)] (doseq [y (range 3)] (prn xy))) 

if you can control the input sequence or like this:

 (let [x-vals (range) y-vals (range) ] (doseq [x x-vals :while (< x 3)] (doseq [y y-vals :while (< y 3)] (prn xy)))) 

if the input sequence (e.g. x-vals or y-vals ) is provided to you from the caller.

0
source

All Articles