How to make Clojure `while` return a value
Can someone explain why Clojure macro while
doesn't return a value?
Looking at the source , it seems like the reason might have something to do with how recursion and macros work, but I don't know enough about the internals of this to speculate.
Example :
The following code returns nil
:
(let [a (atom 0)]
(while (< @a 10)
(+ 1 @a)
(swap! a inc)))
That is, it does not return a value (+ 1 @a)
, nor does it return another value or function that is inside the loop while
. If we want to get some value computed with a loop while
, we could use print
, but then we cannot easily use the value in some other operation. For the return value, we have to use the second atom, for example:
(let [a (atom 0)
end (atom 0)]
(while (< @a 10)
(swap! end #(+ 1 %))
(swap! a inc))
@end)
source to share
Using (source while)
the REPL, we can see that it is implemented like this:
(defmacro while
"Repeatedly executes body while test expression is true. Presumes
some side-effect will cause test to become false/nil. Returns nil"
{:added "1.0"}
[test & body]
`(loop []
(when ~test
~@body
(recur))))
So he performs the body, then checks the condition, rinsing, repeats. By the time the condition is false, the last return value from the body has disappeared.
But what exactly are you trying to do? Do you really need an atom for this?
This code counts up to 10 and returns 10:
(loop [a 0]
(if (< a 10)
(recur (inc a))
a))
source to share
Can someone explain why Clojure doesn't return a value yet?
But can't we ... along with the side effects?
Side effects are there where you need them, but if you are too free to mix them across the entire standard, then you are missing one of the huge benefits of functional programming.
In clojure.core, the "functions" that are used to implement some side effect are always delineated as such, and it is good to follow this in your own code as well.
source to share