2014-11-24 40 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