Closures in Clojure

Clojure supports anonymous functions, which can form closures. Anonymous functions are useful when you want to define a function inline without having to name it.

(ns closures-example
  (:require [clojure.core :refer [println]]))

;; This function `int-seq` returns another function, which
;; we define anonymously in the body of `int-seq`. The
;; returned function closes over the atom `i` to form a closure.
(defn int-seq []
  (let [i (atom 0)]
    (fn []
      (swap! i inc))))

(defn -main []
  ;; We call `int-seq`, assigning the result (a function)
  ;; to `next-int`. This function value captures its
  ;; own `i` value, which will be updated each time
  ;; we call `next-int`.
  (let [next-int (int-seq)]
    
    ;; See the effect of the closure by calling `next-int`
    ;; a few times.
    (println (next-int))
    (println (next-int))
    (println (next-int))
    
    ;; To confirm that the state is unique to that
    ;; particular function, create and test a new one.
    (let [new-ints (int-seq)]
      (println (new-ints)))))

To run this Clojure program:

$ clj -M closures.clj
1
2
3
1

In this Clojure version:

  1. We define int-seq which returns an anonymous function. This function closes over an atom i, forming a closure.

  2. The anonymous function uses swap! to increment the atom and return its new value.

  3. In the -main function, we demonstrate the use of the closure by calling it multiple times and showing how it maintains its own state.

  4. We also create a second closure to show that each instance maintains its own independent state.

The last feature of functions we’ll look at for now is recursion.