3

When I evaluate the following core.async clojurescript code I get an error: "Uncaught Error: <! used not in (go ...) block"

(let [chans [(chan)]]
  (go
   (doall (for [c chans]
     (let [x (<! c)]
       x)))))

What am I doing wrong here? It definitely looks like the <! is in the go block.

2
  • 5
    This is a constraint of go blocks : <! won't work inside a for for instance. See the accepted answer for a similar question. Commented Feb 26, 2015 at 8:30
  • @user229487 please mark the right post as answer Commented Jan 8, 2018 at 13:21

2 Answers 2

5

because go blocks can't cross function boundaries I tend to fall back on loop/recur for a lot of these cases. the (go (loop pattern is so common that it has a short-hand form in core.async that is useful in cases like this:

user> (require '[clojure.core.async :as async])
user> (async/<!! (let [chans [(async/chan) (async/chan) (async/chan)]]
                   (doseq [c chans]
                     (async/go (async/>! c 42)))
                   (async/go-loop [[f & r] chans result []]
                     (if f
                       (recur r (conj result (async/<! f)))
                       result))))
[42 42 42]
Sign up to request clarification or add additional context in comments.

Comments

1

Why dont you use alts! from Core.Async?

This function lets you listen on multiple channels and know which channel you read from on each data.

For example:

(let [chans [(chan)]]
  (go
    (let [[data ch] (alts! chans)]
        data)))))

You can ask of the channel origin too:

...
(let [slow-chan (chan)
      fast-chan (chan)
      [data ch] (alts! [slow-chan fast-chan])]
    (when (= ch slow-chan)
       ...))

From the Docs:

Completes at most one of several channel operations. Must be called inside a (go ...) block. ports is a vector of channel endpoints, which can be either a channel to take from or a vector of [channel-to-put-to val-to-put], in any combination. Takes will be made as if by !. Unless the :priority option is true, if more than one port operation is ready a non-deterministic choice will be made. If no operation is ready and a :default value is supplied, [default-val :default] will be returned, otherwise alts! will park until the first operation to become ready completes. Returns [val port] of the completed operation, where val is the value taken for takes, and a boolean (true unless already closed, as per put!) for put

Doumentation ref

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.