2014-11-24 63 views
3

如果匹配條件返回最後一個值,有沒有辦法突破Clojure中的循環?大多數算法在找到它時返回結果並避免完成整個執行。在Clojure中實現中斷

假設我有一個從0到100範圍內的100個數字的向量,我想找到數字10.一旦找到10,我希望執行停止。

一個比我的例子更簡單情況如下:

(defn MySearch 
    [y] 
    (when (< y 10) 

;;Corrected. Thanks to dsm who pointed it out. Previously was (< y 5). 

     (if (= (nth [1 2 3 4 5 6 7 8 9 10] y) 10) 
      (println 
       "I found it! Now I want to stop executing!" 
      ) 
     ) 
     (recur 
      (inc y) 
     ) 
    ) 
) 

(MySearch 0) 

如何停止的時候我發現5?

我已經搜索了足夠的,我找不到任何方式來實現這一點。我在這裏也找到了一個答案,指出我所問的東西在Clojure中不存在,但我覺得它有點牽強。即使情況是這樣,我可以自己實現這樣的事情嗎?

(我是新來的Clojure。)

+0

你可以在這裏放一些示例代碼嗎? – 2014-11-24 04:49:00

+0

當然,我會立即編輯它! – Adam 2014-11-24 04:49:21

回答

7

你幾乎說得沒錯。重新格式化您的代碼,我們得到

(defn MySearch [y] 
    (when (< y 10) 
    (if (= (nth [1 2 3 4 5 6 7 8 9 10] y) 10) 
     "I found it! Now I want to stop executing!") 
    (recur (inc y)))) 

...這裏 - 爲了簡單 - 我已經擺脫了println的,並有功能有望回覆您。

但是,正如你已經注意到了,它不會:

(MySearch 0) 
;nil 

爲什麼?

麻煩的是(recur ...)if。這是做什麼的?

  • 如果(< y 10)條件爲when滿足時,(if ...)和 的(recur ...)依次被執行,並且後者 的結果返回。
  • 最終,y10,所以when條件失敗,所以when 返回nil

讓移動RECUR if

(defn MySearch [y] 
    (when (< y 10) 
    (if (= (nth [1 2 3 4 5 6 7 8 9 10] y) 10) 
     "I found it! Now I want to stop executing!" 
     (recur (inc y))))) 

現在,你瞧:

(MySearch 0) 
;"I found it! Now I want to stop executing!" 

因爲我們返回消息,我們知道該函數做停止執行。否則,它會繼續並返回nil

隨着println到位,該函數會輸出消息並立即返回nil,就像它在執行時一樣。所以 - 至於它是否停止執行,你並不聰明。


順便說一句,作爲the answer you find far-fetched作者,讓我再試一次:

  • 沒有休息聲明 Clojure中。
  • 這是倒過來:你在默認情況下跳出循環的

    • 您必須使用recur才能繼續。
  • recur是函數(或loop)正在執行一個特殊的遞歸調用:

    • 之一,它是返回值。
    • 據說是在尾部位置

大多數Lisp的系統檢測到這樣的電話 - 所謂尾調用 - 自動。 所以他們沒有或需要像recur這樣的構造。


話雖如此,Clojure的1.5引入了reduced:一個break樣構建減少。你可以閱讀關於它here

+0

非常感謝!優秀的答案!這不是我所指的答案。此外,您放置在超鏈接中的人也很棒,也很有幫助! +1:P – Adam 2014-11-24 18:55:35

3

你並不真的需要一個break語句,因爲Clojure中比它在,比方說,Java的循環作品非常不同。例如,以下內容:

user=> (loop [[x & t] [0 1 2 3 4 5 6 7 8 9]] 
    #_=> (println "x=" x) 
    #_=> (if (= x 5) 
    #_=>  x 
    #_=>  (recur t))) 
x= 0 
x= 1 
x= 2 
x= 3 
x= 4 
x= 5 
5 
user=> 

在java中大致相當於​​。

你必須記住,在clojure loop不是,本身,循環,而是設置一個recur目標。

我建議你去通過Rick Hickey's videos關於這一主題,以熟悉的這個怪異的方面。

編輯:您似乎已經增加了一些代碼,而我是embettering我的迴應,但不用擔心,一個叫功能也易復發的目標,因此,所有我說上面仍然適用:)。這裏是你的代碼重新格式化爲更lisp-y風格:

user=> ; FYI: This function will never print "success" 
user=> (defn my-search 
    #_=> [y] 
    #_=> (if (< y 5) ; <-- Because of this. 
    #_=>  (if (= (nth [1 2 3 4 5 6 7 8 9 10] y) 10) 
    #_=>  (println "Success!") 
    #_=>  (recur (+ y 1))) 
    #_=>  (println "y is >= 5"))) 
#'user/my-search 
user=> (my-search 3) 
y is >= 5 
nil 
user=> 
+0

非常感謝你!我會看看。 – Adam 2014-11-24 05:24:08

+0

我已經寫了這個函數有其他的想法,然後我改變了矢量而不改變條件。感謝您指出! – Adam 2014-11-24 06:19:24

+0

你的回答很有幫助,但另一個人正在回答我所要求的清楚解釋。我必須接受那一個。儘管非常感謝你。:) – Adam 2014-11-24 19:21:02