def
определяет переменную верхнего уровня, даже если вы используете ее в функции или внутреннем цикле некоторого кода. То, что вы получаете в let
, не являются переменными. По документации по let
:
Локальные объекты, созданные с помощью let, не являются переменными. После создания их значения никогда не меняются!
(Акцент не мой.) Вам не нужно изменяемое состояние для вашего примера здесь; Вы можете использовать loop
и recur
.
(loop [x 128]
(when (> x 1)
(println x)
(recur (/ x 2))))
Если вы хотите проявить фантазию, вы можете полностью избежать явного loop
.
(let [xs (take-while #(> % 1) (iterate #(/ % 2) 128))]
(doseq [x xs] (println x)))
Если вы действительно хотели использовать изменяемое состояние, атом может работать.
(let [x (atom 128)]
(while (> @x 1)
(println @x)
(swap! x #(/ %1 2))))
(Вам не нужно do
; while
оборачивает свое тело в явное для вас.) Если вы действительно, действительно хотели сделать это с vars ты должен был бы сделать что-то ужасное, как это.
(with-local-vars [x 128]
(while (> (var-get x) 1)
(println (var-get x))
(var-set x (/ (var-get x) 2))))
Но это очень уродливо и совсем не идиоматично. Чтобы эффективно использовать Clojure, вы должны попытаться перестать думать в терминах изменчивого состояния. Это определенно сведет вас с ума, пытаясь написать код Clojure в не функциональном стиле. Через некоторое время вы можете найти приятным сюрпризом, как редко вам действительно нужны изменяемые переменные.