Closures in Idris
Idris supports anonymous functions, which can form closures. Anonymous functions are useful when you want to define a function inline without having to name it.
import Data.IORef
intSeq : IO (IO Int)
intSeq = do
i <- newIORef 0
pure $ do
modifyIORef i (+1)
readIORef i
main : IO ()
main = do
-- We call intSeq, assigning the result (an IO action) to nextInt.
-- This action captures its own i value, which will be updated
-- each time we call nextInt.
nextInt <- intSeq
-- See the effect of the closure by calling nextInt a few times.
n1 <- nextInt
putStrLn $ show n1
n2 <- nextInt
putStrLn $ show n2
n3 <- nextInt
putStrLn $ show n3
-- To confirm that the state is unique to that particular function,
-- create and test a new one.
newInts <- intSeq
n4 <- newInts
putStrLn $ show n4In this Idris code, we define a function intSeq that returns another IO action. The returned action closes over a mutable reference i to form a closure.
The intSeq function creates a new IORef (a mutable reference in Idris) initialized to 0. It then returns an IO action that, when executed, increments the value in the IORef and returns the new value.
In the main function, we call intSeq and assign the result to nextInt. This nextInt action captures its own i value, which will be updated each time we call it.
We then demonstrate the effect of the closure by calling nextInt multiple times and printing the results. Each call increments and returns the next integer in the sequence.
Finally, to confirm that the state is unique to each closure, we create a new sequence newInts and call it once, showing that it starts from 1 again.
To run this program, you would typically save it in a file with a .idr extension, then use the Idris compiler to compile and run it:
$ idris -o closures closures.idr
$ ./closures
1
2
3
1This example demonstrates how Idris can use closures to maintain state across function calls, similar to other functional programming languages.