为什么Clojure for macro只接受一个身体表达?

时间:2014-07-21 15:18:38

标签: clojure

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循环中的表达式,就像它们在doseqwhen中所做的那样?它不像是有任何语义模糊,对吗?

1 个答案:

答案 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