Range Over Channels in Clojure
In a previous example, we saw how for and range provide iteration over basic data structures. In Clojure, we can use similar concepts to iterate over values received from a channel.
(ns range-over-channels
(:require [clojure.core.async :as async :refer [chan >! <! close! go]]))
(defn main []
; We'll iterate over 2 values in the `queue` channel.
(let [queue (chan 2)]
(>!! queue "one")
(>!! queue "two")
(close! queue)
; This `doseq` iterates over each element as it's
; received from `queue`. Because we closed the
; channel above, the iteration terminates after
; receiving the 2 elements.
(doseq [elem (repeatedly #(<!! queue))]
(println elem))))
(main)To run the program:
$ lein run
one
twoThis example also showed that it’s possible to close a non-empty channel but still have the remaining values be received.
In Clojure, we use the core.async library to work with channels. The chan function creates a channel, >!! puts a value onto a channel, <!! takes a value from a channel, and close! closes a channel.
Instead of using a for loop with range, we use doseq with repeatedly to iterate over the channel. The repeatedly function keeps calling <!! to take values from the channel until it’s closed.
Note that Clojure’s approach to channels and concurrency is somewhat different from some other languages. It provides a rich set of tools for working with asynchronous operations and concurrent programming.