Is there a way to break out of a loop in Clojure if a condition is matched returning the last value? Most algorithms benefit from returning a result when they find it and avoiding completing the whole execution.
Let's say that I have a vector of 100 numbers ranging from 0 to 100 and I want to find the number 10. Once 10 is found I want the execution to stop.
An even simpler case than my example is the following:
(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)
How can I stop when I find 5?
I have searched enough and I can't find any way of implementing this. I have also found an answer here that states that what I am asking doesn't exist in Clojure but I find it a little far-fetched. Even if this is the case can I implement something like that myself?
(I am new to Clojure.)
You nearly got it right. Reformatting your code, we get
(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))))
... where - for simplicity - I've got rid of the println
, and had the function hopefully return your message.
But, as you've noticed, it doesn't:
(MySearch 0)
;nil
Why?
The trouble is that the (recur ...)
is outside the if
. What does this do?
(< y 10)
condition for the when
is met, the (if ...)
and
the (recur ...)
are executed in turn, and the result of the latter
returned. y
is 10
, so the when
condition fails, so the when
returns nil
. Let's move the recur inside the 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)))))
Now, Lo and Behold:
(MySearch 0)
;"I found it! Now I want to stop executing!"
Because we returned the message, we know that the function did stop executing. Otherwise it would have gone on and returned nil
.
With the println
in place, the function would output the message and return nil
immediately, as it would do had it gone on executing. So - as to whether it stopped executing, you're none the wiser.
By the way, as the author of the answer you find far-fetched, let me try again:
It's the other way round:
recur
to continue it. recur
is a special recursive call to the function (or loop
) you are executing:
Most Lisp systems detect such calls - so called tail calls - automatically.
So they don't have or need a construct like recur
.
Having said that, Clojure 1.5 introduced reduced
: a break
-like construct for reduce. You can read about it here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With