clojure中是否有类似”:until”的命令?

Is there a “:until” like command in clojure?

我想执行以下嵌套操作,直到满足表达式要求为止。是否存在:until关键字,当条件匹配时,该关键字会停止进行进一步的操作。 。我不希望它一旦到达那个数字序列就做任何其他事情。

1
2
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))


:whilefor表达式中的短路测试。列表元素将一直生成,直到它第一次遇到失败的测试。

在您的情况下,

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

一旦发现三元组的总和为12,就会停止生成元素。 >

尽管有一个问题,但它没有达到您的期望。三元组本身不会成为结果的一部分,因为它未通过测试。

如果只想查找单个匹配结果,列表理解可能不是最佳解决方案。为什么不只使用循环?

1
2
3
4
5
6
7
8
9
(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)))))


由于产生一个惰性序列,因此您可以通过选择第一个元素来获得所需的结果:

1
2
3
4
5
6
(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))

由于懒惰,仅计算生成列表的第一个元素,可以用副作用:

1
2
3
4
5
6
7
8
9
10
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包装在列表中:

1
2
3
4
5
6
(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))