0

I am well-aware of the difference between doseq and for, but the two seem extremely similar. In fact, it seems to me like doseq could easily be implemented as a macro in terms of for.

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

Are there any functional differences between this implementation and Clojure's implementation of doseq, or are they effectively the same (modulo some possible performance differences)?

Community
  • 1
  • 1
Alexis King
  • 43,109
  • 15
  • 131
  • 205

1 Answers1

2

from a practical perspective the fact that for returns a lazy sequence means that it won't work in core.async where doseq does because it runs entirely within the same function.

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

using 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)

fails because it tries to cross a function call within a go block and hence escapes from the go macro's scope.

Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284