Puzzled: Clojure для цикла с: while → неожиданным поведением?
Я изучал Clojure и озадачен следующим:
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_
Добавьте add :while (not= a b)
, я ожидаю увидеть пустой список, поскольку цикл должен остановиться, если условие ложно. В этом случае это самый первый элемент, где a
= b
= 1. Давайте посмотрим:
user=> (for [a (range 1 4) b (range 1 4) :while (not= a b) ] [a b])
([2 1] [3 1] [3 2]) ; _surprise!_
Изменение :while
на :when
для фильтрации (= a b)
пар
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_
Может ли кто-нибудь объяснить, почему (for [ ... :while ..] ...)
ведет себя так?
Я использую Clojure 1.3 для OS X.
Благодарим вас и извиниться за отсутствие форматирования. Это мой девственный пост в StackOverflow.
Ответы
Ответ 1
Посмотрим на каждую итерацию.
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
Ответ 2
Условие :while
в for
завершает цикл только самого внутреннего. Я использую for
все время, но :while
так редко, что я никогда не осознавал этого; спасибо за большой вопрос!
К сожалению, самое лучшее, что вы можете сделать, это обернуть take-while
вокруг for
, так как вам нужен "глобальный" стоп-счетчик в выходной последовательности, а не стоп-счетчик на одной из входных последовательностей, которые вы "повторять". Например:
(->> (for [a (range 1 4)
b (range 1 4)]
[a b])
(take-while (fn [[a b]] (not= a b))))
()