我很清楚doseq
和for
之间的区别,但两者看起来非常相似。事实上,在我看来,doseq
可以很容易地作为for
的宏来实现。
(defmacro doseq' [bindings & body]
`(dorun (for ~bindings ~@body)))
这个实现和Clojure的doseq
实现之间是否有任何功能差异,或者它们实际上是相同的(模取一些可能的性能差异)?
从实际的角度来看,for
返回一个惰性序列的事实意味着它不会在核心中工作。因为doseq完全运行在同一个函数中,所以它是异步的。
user> (require '[clojure.core.async :refer [chan go <! <!! >!]])
使用doseq: user> (let [stuff (chan)]
(go (while true
(println (<! stuff))))
(go (doseq [a (range 4)]
(>! stuff a))))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x523a18bc "clojure.core.async.impl.channels.ManyToManyChannel@523a18bc"]
user> 0
1
2
3
using for and dorun:
user> (let [stuff (chan)]
(go (while true
(println (<! stuff))))
(go (dorun (for [a (range 4)]
(>! stuff a)))))
CompilerException java.lang.IllegalArgumentException: No method in multimethod '-item-to-ssa' for dispatch value: :fn, compiling:(form-init5662188991458325584.clj:4:9)
失败是因为它试图在go块内交叉函数调用,因此从go宏的作用域中转义。