在Clojure中实现break

时间:2014-11-24 04:42:05

标签: clojure

如果匹配条件返回最后一个值,有没有办法在Clojure中打破循环?大多数算法都会在找到结果时返回结果并避免完成整个执行。

假设我有一个100个数字的向量,范围从0到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的新手。)

2 个答案:

答案 0 :(得分:12)

你几乎做对了。重新格式化代码,我们得到

(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)的{​​{1}}条件,when(if ...) (recur ...)依次执行,后者的结果 回。
  • 最终,y10,因此when条件失败,因此when 返回nil

让我们在<{1}}:

中移动
if

现在,Lo和Behold:

(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,就像它执行时一样。那么 - 至于它是否停止执行,你就不是更聪明了。


顺便说一下,作为the answer you find far-fetched的作者,让我再试一次:

  • Clojure中没有中断语句
  • 反过来说:

    • 默认情况下,您会跳出循环。
    • 您必须使用nil才能继续。
  • recur是对正在执行的函数(或recur)的特殊递归调用:

    • 返回值的一个。
    • 据说处于尾部位置

大多数Lisp系统会自动检测此类调用 - 所谓的尾调用。 所以他们没有或不需要像loop这样的结构。


话虽如此,Clojure 1.5引入了recurreduced - 类似于reduce的构造。你可以阅读它here

答案 1 :(得分:4)

你真的不需要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中的if(x == 5) break;

你必须记住,在clojure中loop本身不会循环,而是设置一个recur目标。

我建议你浏览一下这个主题的Rick Hickey's videos,以便熟悉这个问题。

编辑:你似乎在我的反应中添加了一些代码,但不用担心,命名函数也是一个重复目标,所以我上面说的所有代码仍然适用:)。这是您的代码以更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=>