Есть ли команда ": до" в clojure? - PullRequest
       21

Есть ли команда ": до" в clojure?

4 голосов
/ 02 августа 2009

Я хочу выполнить следующие вложенные операции, пока выражение не будет выполнено. Существует ли ключевое слово: before, которое прекращает выполнение дальнейших операций при совпадении условия .?

Эта команда генерирует тройку Пифагора 3 4 5. Я не хочу, чтобы она делала что-либо еще, когда доберется до этой последовательности чисел.

(for [a (range 1 100)
      b (range 1 100)
      c (list (Math/sqrt (+ (Math/pow (int a) 2) (Math/pow (int b) 2))))
      :when (= 12 (+ a b c))]
     (list a b c))

Ответы [ 2 ]

9 голосов
/ 02 августа 2009

:while - это тест на короткое замыкание в выражениях for. Элементы списка будут создаваться до тех пор, пока в первый раз он не встретит неудачный тест.

В вашем случае

(for [<code omitted> :while (not (= 12 (+ a b c)))] (list a b c))

перестанет генерировать элементы, как только найдет триплет, суммирующий до 12.

Одна проблема, однако, это не делает то, что вы ожидаете. Сам триплет не был бы частью результата, поскольку он не прошел тест.

Понимание списка может быть не лучшим решением, если вы ищете только один соответствующий результат. Почему бы просто не использовать цикл?

(loop [xs (for [a (range 1 100)
                b (range 1 100)] [a, b])]
  (when (seq xs)
    (let [[a, b] (first xs)
          c (Math/sqrt (+ (Math/pow (int a) 2)
                          (Math/pow (int b) 2)))]
      (if (not (= 12 (+ a b c)))
        (recur (next xs))
        (list a b c)))))
6 голосов
/ 03 августа 2009

Поскольку для дает последовательность lazy , вы получите желаемый результат, выбрав первый элемент:

(first (for [a (range 1 100)
             b (range 1 100)
             c (list (Math/sqrt (+ (Math/pow (int a) 2) 
                                   (Math/pow (int b) 2))))
             :when (= 12 (+ a b c))]
          (list a b c))

Из-за лени вычисляется только первый элемент сгенерированного списка, что может быть продемонстрировано с побочным эффектом:

user=> (first
        (for [a (range 1 100)
              b (range 1 100)
              c (list (Math/sqrt (+ (Math/pow (int a) 2) 
                                    (Math/pow (int b) 2))))
              :when (= 12 (+ a b c))]
          (do (println "working...")
              (list a b c))))
working...
(3 4 5.0)

(for ...) поставляется с модификатором: let, поэтому нет необходимости заключать c в список:

(for [a (range 1 100)
      b (range 1 100)
      :let [c (Math/sqrt (+ (Math/pow (int a) 2) 
                            (Math/pow (int b) 2)))]
      :when (= 12 (+ a b c))]
  (list a b c))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...