Clojure中doseq和for之间的区别

Posted

技术标签:

【中文标题】Clojure中doseq和for之间的区别【英文标题】:Difference between doseq and for in Clojure 【发布时间】:2011-06-11 03:47:15 【问题描述】:

在 Clojure 中,doseq 和 for 有什么区别?有哪些示例说明您何时会选择使用其中一种?

【问题讨论】:

【参考方案1】:

不同之处在于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。

【讨论】:

现在有很多副作用......发射核弹头:) 谢谢!我用“因为”拉着我的(早已消失的)头发,它永远不会在我的物品清单上发射我的核弹头。 “剂量”确实做到了。 这是一个很好的区分方式。【参考方案2】:

还要注意doseq 是急切的,而for 是懒惰的。 Rayne 的回答中缺少的示例是

(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 将引用未实现的惰性序列:没有它的元素已经计算过了。 eager 将引用nil,并且它的所有打印都将完成。

【讨论】:

doseq 如何处理无限惰性序列的求值?馊主意?只在有限序列上调用它,无论是急切的还是懒惰的? @johnbakers 它将永远阻塞,直到评估被中断。 Clojure 从不尝试以与有限序列不同的方式处理无限序列。

以上是关于Clojure中doseq和for之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

Clojure 1.8的套接字repl和nREPL之间的具体区别是什么?

Scala,Groovy,Clojure三门语言的区别

Clojure 内容类型?

如何使用clojure.spec生成相互关联的args?

Clojure:减少与应用

clojure for function resetts let