How to make Clojure `while` return a value

Can someone explain why Clojure macro while

doesn't return a value?

The documentation says, "Assuming some side effect will cause the test to become false / null." Ok, so we use swap!

to change the atom that is used in the test case. But we can't have a return value (possibly repeating itself, as in the case of c loop

) along with side effects?

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)

      

+3


source to share


2 answers


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))

      

+3


source


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.

+1


source







All Articles