Озадаченный: Clojure для цикла с: while -> неожиданным поведением? - PullRequest
12 голосов
/ 11 января 2012

Я изучаю 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_

Давайте добавим :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.

Ответы [ 2 ]

9 голосов
/ 11 января 2012

Давайте посмотрим на каждую итерацию.

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
3 голосов
/ 11 января 2012

Условие :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))))

()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...