in Clojure, one can iterate over a sequence by the help of the function for
or similarly with doseq
for side-effects and getting nil as return value:
(doseq [x (range 3)]
(prn x))
; 0
; 1
; 2
for the case the sequence is infinite, there is a way to introduce a break condition:
(doseq [x (range) :while (< x 3)]
(prn x))
This would produce the same output as above.
As a specialty there is a very interesting behavior when you use more than one sequence. As the documentation calls it: "Collections are iterated in a nested fashion, rightmost fastest".
(doseq [x (range 3) y (range 3)]
(prn x y))
; 0 0
; 0 1
; 0 2
; 1 0
; 1 1
; 1 2
; 2 0
; 2 1
; 2 2
What happens however, if the sequences are infinite again. When the last one is infinite, it works quite well. this would work equally as the example before:
(doseq [x (range 3) y (range) :while (< y 3)]
(prn x y))
If the first one is infinite, the resulting output is as expected, but for some reasons the loop does not stop after the last line is printed. In other words: the repl keeps working.
(doseq [x (range) y (range 3) :while (< x 3)]
(prn x y))
Can anybody explain this behavior?
This doesn't make sense:
(doseq [x (range)
y (range 3)
:while (< x 3)]
(prn x y))
It should be:
(doseq [x (range)
:while (< x 3)
y (range 3)]
(prn x y))
...which terminates.
Think of it this way:
(doseq [x (range)]
(doseq [y (range 3)
:while (< x 3)]
(prn x y)))
vs:
(doseq [x (range)
:while (< x 3)]
(doseq [y (range 3)]
(prn x y)))
In the original version, outer loop is infinite, having that :while
in the inner loops doesn't make a difference. The loop continues on, it just does nothing. In the fixed version :while
terminates the outer loop.
Given muhuk's excellent explanation, it seems like a good argument for being explicit and not over-compressing the code. So maybe like this:
(doseq [x (range 3)]
(doseq [y (range 3)]
(prn x y)))
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 x y))))
if the input sequence (eg x-vals
or y-vals
) is provided to you from the caller.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With