【问题标题】:Why does Clojure's for macro only accept one body expression?为什么 Clojure 的 for 宏只接受一个 body 表达式?
【发布时间】:2014-07-21 15:18:38
【问题描述】:

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 的设计者不允许在 for 循环中使用多个“body”表达式,就像他们在 doseqwhen 中所做的那样?好像没有语义歧义吧?

【问题讨论】:

  • 一个很大的区别是for 是惰性的,而doseq(主要用于引起副作用)不是。 when 在隐式 do 中评估其主体。另见stackoverflow.com/q/4725417

标签: clojure


【解决方案1】:

Clojure 的for 不是循环,它是惰性列表理解。由于仅返回(隐式)do 主体中最后一个表达式的值,因此任何其他表达式都必须仅出于副作用而存在。副作用的执行是doseq 的工作,这就是为什么它有一个隐含的dofor 不应该是一个提醒,你真的想要你的惰性序列中的副作用吗?尽管这样做是有正当理由的,但需要注意的是,这些副作用会在您需要时执行。

(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

【讨论】:

  • 一个很好的答案,虽然我认为最后的分块部分主要是一个红鲱鱼,并且解释得不够好,无论如何都没有用。
猜你喜欢
  • 2014-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
相关资源
最近更新 更多