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
two
This 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.