关于clojure:doseq和dorun联合使用之间有什么区别吗?

Are there any differences between doseq and for combined with dorun?

我很清楚doseqfor之间的区别,但是两者似乎极为相似。 实际上,在我看来,doseq可以很容易地根据for实施为宏。

1
2
(defmacro doseq' [bindings & body]
  `(dorun (for ~bindings ~@body)))

此实现与Clojure的doseq实现之间是否存在功能上的区别,或者它们实际上是相同的(对某些可能的性能差异进行模运算)?


从实际的角度来看,for返回延迟序列这一事实意味着它无法在core.async中工作,而剂量q却可以这样做,因为它完全在同一函数中运行。

1
user> (require '[clojure.core.async :refer [chan go <! <!! >!]])

使用剂量q:

1
2
3
4
5
6
7
8
9
10
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

使用for和dorun:

1
2
3
4
5
6
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宏的作用域。