2009-08-02 52 views
4

我想执行下列嵌套操作,直到满足预期为止。 是否存在:until关键字,当条件匹配时停止进一步操作。在clojure中是否存在“:until”命令?

这个命令会生成Pythagoran Triplet 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)) 
+1

难道你不能只是“不”吗? – jrockway 2009-08-02 16:12:42

回答

9

:whilefor表达式一个短路测试。列表元素将在第一次遇到失败的测试时生成。

在你的情况

(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))))) 
+0

我从这段代码中学到了很多东西。只是几个问题:1.什么类型(用于......)生成?你为什么需要(seq xs)? – unj2 2009-08-02 19:02:34

+0

1)懒惰的序列。 2)检查xs为空时的情况:当xs为空时,(seq xs)将返回nil,从而使测试失败并退出循环。这在Clojure中是相当常见的成语。 – alanlcode 2009-08-02 19:59:43

6

由于for产生一个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 ...)来:与副作用证明s带有: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)) 
相关问题