Clojure的for
宏接受两个参数:一系列绑定表单和一个正文表达式。因此,如果我想在循环中做多个事情,我必须在do
块中包含多个表达式,使它们成为单个表达式。
比较
(doseq [a (range 3)]
(prn 'a a)
(inc a))
为:
(for [a (range 3)]
(prn 'a a)
(inc a))
doseq
按预期工作。 for
抱怨:
clojure.lang.ArityException: Wrong number of args (3) passed to: core/for
我的问题是,为什么这不起作用?为什么Clojure的设计师不允许使用多个" body" for循环中的表达式,就像它们在doseq
和when
中所做的那样?它不像是有任何语义模糊,对吗?
答案 0 :(得分:14)
Clojure的for
不是循环,它是懒惰列表理解。由于仅返回(隐式)do
的主体中的最后一个表达式的值,因此仅存在副作用的任何其他表达式。副作用的执行是doseq
的工作,这就是它具有隐式do
的原因。那for
不应该是一个提醒,你真的想要懒惰序列中的副作用吗?尽管有合理的理由这样做,但需要注意的是,这些副作用会在您想要的时候执行。
(def foo (for [a (range 32)]
(do
(prn (str "a is " a))
(inc a))))
(take 1 foo)
;=>
("a is 0"
"a is 1"
...
"a is 31"
1) ; <= the return value
(take 10 foo)
;=>
(1 2 3 4 5 6 7 8 9 10) ; aw, no side effects this time