Closures in Miranda

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

import java.util.function.Supplier;

public class Closures {
    // This method returns a Supplier<Integer>, which is similar to a function
    // that takes no arguments and returns an integer. The returned lambda
    // expression closes over the variable i to form a closure.
    public static Supplier<Integer> intSeq() {
        int[] i = {0};  // We use an array to simulate a mutable integer
        return () -> ++i[0];
    }

    public static void main(String[] args) {
        // We call intSeq, assigning the result (a Supplier<Integer>)
        // to nextInt. This lambda captures its own i value, which will
        // be updated each time we call nextInt.get().
        Supplier<Integer> nextInt = intSeq();

        // See the effect of the closure by calling nextInt.get()
        // a few times.
        System.out.println(nextInt.get());
        System.out.println(nextInt.get());
        System.out.println(nextInt.get());

        // To confirm that the state is unique to that
        // particular function, create and test a new one.
        Supplier<Integer> newInts = intSeq();
        System.out.println(newInts.get());
    }
}

To run this program:

$ javac Closures.java
$ java Closures
1
2
3
1

In this Java version, we use a Supplier<Integer> to represent a function that takes no arguments and returns an integer. The intSeq method returns a lambda expression that captures and increments a local variable.

Java doesn’t allow modifying local variables from within lambda expressions, so we use an array with a single element to simulate a mutable integer. This is a common workaround in Java when dealing with closures that need to modify captured variables.

The main method demonstrates how the closure maintains its own state, incrementing the captured variable with each call. Creating a new Supplier<Integer> with intSeq() results in a new, independent counter, as shown by the final output of 1.

This example showcases how Java can implement closure-like behavior using lambda expressions and functional interfaces, providing a way to create and use anonymous functions with state.

The next topic we’ll explore is recursion.