有人可以解释为什么Clojure的while
宏没有返回值吗?
documentation说“推定
一些副作用会导致测试变为false / nil。“好的,我们使用swap!
来修改测试用例中使用的原子。但是我们还不能有一个返回值(可能会重复返回) ,如loop
)的情况,带的副作用?
看看source,似乎原因可能与递归和宏如何工作有关,但我不太了解推测它的内部结构。
示例:
以下代码仅返回nil
:
(let [a (atom 0)]
(while (< @a 10)
(+ 1 @a)
(swap! a inc)))
也就是说,它不返回(+ 1 @a)
的值,也不返回while
循环内的任何其他值或函数。如果我们想通过while
循环计算一些值,我们可以使用print
,但是我们不能在其他一些操作中轻松使用该值。对于返回值,我们必须使用第二个原子,如下所示:
(let [a (atom 0)
end (atom 0)]
(while (< @a 10)
(swap! end #(+ 1 %))
(swap! a inc))
@end)
答案 0 :(得分:3)
在REPL上使用(source while)
,我们可以看到它是这样实现的:
(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))))
所以,它执行身体,然后检查条件,冲洗,重复。当条件为假时,身体的最新返回值消失了。
但你究竟想做什么?你真的需要一个原子吗?
此代码最多可计入10并返回10:
(loop [a 0]
(if (< a 10)
(recur (inc a))
a))
答案 1 :(得分:1)
有人可以解释为什么Clojure会在宏观没有返回值时解释?
但我们仍然可以...... 带副作用吗?
当你需要时会产生副作用,但如果你在常规代码中过于自由地混合它们,那么你就会错过函数式编程的巨大好处之一。
在clojure.core中,&#39;功能&#39;用于实现某些副作用的目的总是如此划分,并且在您自己的代码中也遵循这一点是个好主意。