Tickers in Clojure

Our example demonstrates how to use tickers in Clojure. Tickers are used when you want to perform an action repeatedly at regular intervals.

(ns tickers-example
  (:require [clojure.core.async :refer [chan go-loop <! >! timeout close!]]))

(defn ticker []
  (let [ticker-chan (chan)
        done-chan (chan)]
    (go-loop []
      (let [[val channel] (alts! [(timeout 500) done-chan])]
        (if (= channel done-chan)
          (println "Ticker stopped")
          (do
            (>! ticker-chan (java.time.LocalDateTime/now))
            (recur)))))
    [ticker-chan done-chan]))

(defn main []
  (let [[ticker-chan done-chan] (ticker)]
    (go-loop []
      (when-let [t (<! ticker-chan)]
        (println "Tick at" t)
        (recur)))
    
    (Thread/sleep 1600)
    (>!! done-chan true)
    (close! ticker-chan)
    (close! done-chan)))

(main)

In this Clojure version, we use core.async to create channels and manage concurrency, which is similar to Go’s goroutines and channels.

We define a ticker function that creates two channels: ticker-chan for sending tick values, and done-chan for signaling when to stop. The function uses go-loop to repeatedly send the current time to ticker-chan every 500 milliseconds, unless a value is received on done-chan.

In the main function, we start the ticker and print each tick. After 1600 milliseconds, we signal the ticker to stop by sending a value to done-chan.

When we run this program, the ticker should tick 3 times before we stop it:

$ lein run
Tick at 2023-06-01T10:30:00.123
Tick at 2023-06-01T10:30:00.623
Tick at 2023-06-01T10:30:01.123
Ticker stopped

This example demonstrates how to implement tickers in Clojure using core.async, providing functionality similar to Go’s tickers.