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
1In this Standard ML version:
We define
intSeqas a function that returns another function. The inner function captures the referenceiin its closure.We use a reference (
ref) to create mutable state, as Standard ML is primarily a functional language.The anonymous function returned by
intSeqincrements the reference and returns its value.In the main part of the program, we demonstrate the use of the closure by calling
nextIntmultiple times and then creating a new closure withnewInts.We use
printandInt.toStringto 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.