Clojure中的dq和for之间的差异


105

在Clojure中,doseq和for有什么区别?什么时候您会选择使用一个而不是另一个呢?

Answers:


167

区别在于for建立一个惰性序列并返回它,而doseq执行副作用则返回nil。

user=> (for [x [1 2 3]] (+ x 5))
(6 7 8)
user=> (doseq [x [1 2 3]] (+ x 5))
nil
user=> (doseq [x [1 2 3]] (println x))
1
2
3
nil

如果要基于其他序列构建新序列,请使用for。如果要基于某些序列中的元素产生副作用(打印,写入数据库,发射核弹头等),请使用doseq。


11
现在有很多副作用...发射核弹头:)
Marc

6
谢谢!我曾经(长期以来)拔头发,因为它永远不会将我的核弹头发射到我的物品清单上。“ doseq”肯定做到了。
俞申

这是区分的好方法。
jskulski

60

还请注意,懒惰时doseq渴望for。雷恩答案中缺少的示例是

(for [x [1 2 3]] (println x))

在REPL上,这通常会做您想要的事情,但这基本上是一个巧合:REPL强制由产生的惰性序列for,从而导致printlns发生。在非交互式环境中,不会打印任何内容。您可以通过比较以下结果来了解实际情况

user> (def lazy (for [x [1 2 3]] (println 'lazy x)))
#'user/lazy

user> (def eager (doseq [x [1 2 3]] (println 'eager x)))
eager 1
eager 2
eager 3
#'user/eager

因为def表单返回的是新创建的var,而不是绑定的值,所以REPL没有要打印的内容,并且lazy将引用未实现的lazy-seq:根本没有计算任何元素。eager将参考nil,并且其所有打印都将完成。


剂量q如何处理无限延迟序列的求值?馊主意?只在有限的序列上称呼它,渴望还是懒惰?
johnbakers 2014年

@johnbakers它将永远阻塞直到评估被中断。Clojure绝不会尝试以与有限序列不同的方式来处理无限序列。
Radon Rosborough,2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.