Closures in F#
F# supports anonymous functions, which can form closures. Anonymous functions are useful when you want to define a function inline without having to name it.
open System
// 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.
let intSeq () =
let mutable i = 0
fun () ->
i <- i + 1
i
// 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'.
let nextInt = intSeq()
// See the effect of the closure by calling 'nextInt'
// a few times.
printfn "%d" (nextInt())
printfn "%d" (nextInt())
printfn "%d" (nextInt())
// To confirm that the state is unique to that
// particular function, create and test a new one.
let newInts = intSeq()
printfn "%d" (newInts())
To run the program, save it as Closures.fs
and use the F# compiler (fsc
) to compile it, then run the resulting executable:
$ fsharpc Closures.fs
$ mono Closures.exe
1
2
3
1
In F#, closures work similarly to other functional programming languages. The intSeq
function returns an anonymous function that increments and returns a mutable variable i
. Each time this anonymous function is called, it increments its own private copy of i
.
The nextInt
and newInts
variables are bound to separate instances of this anonymous function, each with its own state. This demonstrates how closures in F# can maintain state between function calls.
The last feature of functions we’ll look at for now is recursion.