I've been learning Clojure and puzzled by the following:
user=> (for [a (range 1 4) b (range 1 4)] [a b])
([1 1] [1 2] [1 3] [2 1] [2 2] [2 3] [3 1] [3 2] [3 3]); _no surprise here_
Let's add :while (not= a b)
, I expect to see an empty list as the loop should stop if the condition is false. In this case it's the very first item where a
=b
=1. Let's see:
user=> (for [a (range 1 4) b (range 1 4) :while (not= a b) ] [a b])
([2 1] [3 1] [3 2]) ; _surprise!_
Changing :while
to :when
to filter out (= a b)
pairs
user=> (for [a (range 1 4) b (range 1 4) :when (not= a b) ] [a b])
([1 2] [1 3] [2 1] [2 3] [3 1] [3 2]); _expected_
Could anyone explain why (for [ ... :while ..] ...)
behaves like this?
I'm using Clojure 1.3 on OS X.
Thank you and apologize for the lack of formatting. This is my virgin post on StackOverflow.
Let's look at each iteration.
a = 1
b = 1 -> a == b, break because of while
a = 2
b = 1 -> a != b, print [2 1]
b = 2 -> a == b, break because of while
a = 3
b = 1 -> a != b, print [3 1]
b = 2 -> a != b, print [3 2]
b = 3 -> a == b, break because of while
The :while
condition in for
only terminates the inner-most loop. I use for
all the time, but :while
so rarely that I never realized this; thanks for the great question!
Sadly I think the best you can do is wrap a take-while
around the for
, since you want a "global" stop-counter on the output sequence, not a stop-counter on one of the input sequences you're iterating over. For example:
(->> (for [a (range 1 4)
b (range 1 4)]
[a b])
(take-while (fn [[a b]] (not= a b))))
()
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