def
defines a toplevel var, even if you use it in a function or inner loop of some code. What you get in let
are not vars. Per the documentation for let
:
Locals created with let are not variables. Once created their values never change!
(Emphasis not mine.) You don't need mutable state for your example here; you could use loop
and recur
.
(loop [x 128]
(when (> x 1)
(println x)
(recur (/ x 2))))
If you wanted to be fancy you could avoid the explicit loop
entirely.
(let [xs (take-while #(> % 1) (iterate #(/ % 2) 128))]
(doseq [x xs] (println x)))
If you really wanted to use mutable state, an atom might work.
(let [x (atom 128)]
(while (> @x 1)
(println @x)
(swap! x #(/ %1 2))))
(You don't need a do
; while
wraps its body in an explicit one for you.) If you really, really wanted to do this with vars you'd have to do something horrible like this.
(with-local-vars [x 128]
(while (> (var-get x) 1)
(println (var-get x))
(var-set x (/ (var-get x) 2))))
But this is very ugly and it's not idiomatic Clojure at all. To use Clojure effectively you should try to stop thinking in terms of mutable state. It will definitely drive you crazy trying to write Clojure code in a non-functional style. After a while you may find it to be a pleasant surprise how seldom you actually need mutable variables.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…