2009-08-02 54 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)) 
相關問題