Closures in Standard ML
Standard ML supports anonymous functions, which can form closures. Anonymous functions are useful when you want to define a function inline without having to name it.
(* This function intSeq returns another function, which
we define anonymously in the body of intSeq. The
returned function closes over the variable i to
form a closure. *)
fun intSeq () =
let
val i = ref 0
in
fn () => (i := !i + 1; !i)
end;
(* We call intSeq, assigning the result (a function)
to nextInt. This function value captures its
own i value, which will be updated each time
we call nextInt. *)
val nextInt = intSeq ();
(* See the effect of the closure by calling nextInt
a few times. *)
val _ = print (Int.toString (nextInt ()) ^ "\n");
val _ = print (Int.toString (nextInt ()) ^ "\n");
val _ = print (Int.toString (nextInt ()) ^ "\n");
(* To confirm that the state is unique to that
particular function, create and test a new one. *)
val newInts = intSeq ();
val _ = print (Int.toString (newInts ()) ^ "\n");
To run this Standard ML program, you would typically save it to a file (e.g., closures.sml
) and then use an SML interpreter or compiler. For example, if you’re using Standard ML of New Jersey (SML/NJ):
$ sml closures.sml
1
2
3
1
In this Standard ML version:
We define
intSeq
as a function that returns another function. The inner function captures the referencei
in its closure.We use a reference (
ref
) to create mutable state, as Standard ML is primarily a functional language.The anonymous function returned by
intSeq
increments the reference and returns its value.In the main part of the program, we demonstrate the use of the closure by calling
nextInt
multiple times and then creating a new closure withnewInts
.We use
print
andInt.toString
to output the results, as Standard ML doesn’t have a direct equivalent to Go’sfmt.Println
.
This example demonstrates how closures work in Standard ML, capturing and maintaining state between function calls.