I am trying to figure out core.async in my REPL and am completely confused as to how my usage of (go-loop ...) doesn't manage to qualify as a "go block" for the purpose of async/>!
My go-loop is like...
(async/go-loop [page (range 3)]
(if (empty? page)
(async/close! ch)
(dorun (map (fn [row]
(println row)
(async/>! ch row)) page)))
(recur (range (dec (count page)))))
But the REPL is all upset...
=>
#object[clojure.core.async.impl.channels.ManyToManyChannel
0x23465937
"clojure.core.async.impl.channels.ManyToManyChannel@23465937"]
0
Exception in thread "async-dispatch-12" java.lang.AssertionError: Assert failed: >! used not in (go ...) block
nil
...
Why isn't the scope of that (go-loop ...)
sufficient for the (async/>! row)
call?
Should I even be using a go-loop here?
>!
and other parking calls can't be used inside of functions nested inside of a go
unfortunately.
go
turns the code you give it into a state machine and looks for parking calls. It doesn't however look inside of nested functions.
From Clojure.Asyncs Github best practice page:
Unsupported constructs and other limitations in go blocks
The go macro stops translating at function creation boundaries. This means the following code will fail to compile, or may just throw a runtime error stating that
<!
was used outside of a go block:(go (let [my-fn (fn [] (<! c))] (my-fn)))
This is one thing to remember since many Clojure constructs create functions inside macros. The following are examples of code that will not work as one would expect:
(go (map <! some-chan)) (go (for [x xs] (<! x)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With