Closures in Racket

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

#lang racket

; This function `int-seq` returns another function, which
; we define anonymously in the body of `int-seq`. The
; returned function closes over the variable `i` to
; form a closure.
(define (int-seq)
  (let ([i 0])
    (lambda ()
      (set! i (add1 i))
      i)))

; 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`.
(define next-int (int-seq))

; See the effect of the closure by calling `next-int`
; a few times.
(displayln (next-int))
(displayln (next-int))
(displayln (next-int))

; To confirm that the state is unique to that
; particular function, create and test a new one.
(define new-ints (int-seq))
(displayln (new-ints))

To run the program, save it to a file (e.g., closures.rkt) and use the racket command:

$ racket closures.rkt
1
2
3
1

In this Racket version, we define int-seq as a function that returns another function. This inner function closes over the i variable, creating a closure. Each time the inner function is called, it increments and returns the value of i.

We demonstrate the use of this closure by creating next-int and calling it multiple times. We then create a new closure new-ints to show that its state is independent of next-int.

Racket’s support for closures allows for elegant and powerful functional programming patterns, enabling the creation of stateful functions and encapsulation of data.

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