clojure.async: ‹! не в (перейти) ошибка блока

Когда я оцениваю следующий код clojurescript core.async, я получаю сообщение об ошибке: «Uncaught Error: ‹! Используется не в блоке (go...)»

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

Что я здесь делаю неправильно? Это определенно похоже на ‹! находится в блоке go.


person user229487    schedule 26.02.2015    source источник
comment
Это ограничение go блоков: <! не будет работать, например, внутри for. См. принятый ответ на аналогичный вопрос. .   -  person T.Gounelle    schedule 26.02.2015
comment
@user229487, пожалуйста, отметьте правильный пост как ответ   -  person Itamar    schedule 08.01.2018


Ответы (2)


поскольку блоки go не могут пересекать границы функций, я склонен прибегать к циклу/повторению во многих таких случаях. шаблон (go (loop настолько распространен, что имеет сокращенную форму в core.async, которая полезна в таких случаях:

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]
person Arthur Ulfeldt    schedule 26.02.2015

Почему бы вам не использовать alts! из Core.Async?

Эта функция позволяет прослушивать несколько каналов и знать, с какого канала вы считываете данные.

Например:

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

Вы также можете спросить о происхождении канала:

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

Из Документов:

Завершает не более одной из нескольких операций канала. Должен вызываться внутри блока (go...). ports — это вектор конечных точек канала, который может быть либо каналом для получения, либо вектором [channel-to-put-to val-to-put] в любой комбинации. Дубли будут сделаны как бы !. Если параметр :priority не равен true, если более чем одна операция порта готова, будет сделан недетерминированный выбор. Если ни одна операция не готова и задано значение :default, будет возвращено значение [default-val :default], иначе alts! будет парковаться до тех пор, пока не завершится первая операция, которая должна стать готовой. Возвращает [val port] завершенной операции, где val — это значение, взятое для дублей, и логическое значение (true, если оно еще не закрыто, согласно put!)

Документация ссылка

person Itamar    schedule 20.05.2017