Supply is:module

A fast unique identifier supply with local pooling and replay support. One often has a desire to generate a bunch of integer identifiers within a single process that are unique within that process. You could use UUIDs, but they can be expensive to generate; you don't want to have your threads contending for a single external counter if the identifier is not going to be used outside the process. concurrent-supply builds a tree-like structure which can be split; you can make smaller unique supplies and then you allocate from your supplies locally. Internally it pulls from a unique supply one block at a time as you walk into parts of the tree that haven't been explored.
A fast unique identifier supply with local pooling and replay support. One often has a desire to generate a bunch of integer identifiers within a single process that are unique within that process. You could use UUIDs, but they can be expensive to generate; you don't want to have your threads contending for a single external counter if the identifier is not going to be used outside the process. concurrent-supply builds a tree-like structure which can be split; you can make smaller unique supplies and then you allocate from your supplies locally. Internally it pulls from a unique supply one block at a time as you walk into parts of the tree that haven't been explored.
This library can be used to generate values (for example, new names) without the need to thread state. This means that functions that need to generate new values only need a supply object as an argument, and they do not need to return a new supply object as a result. This decreases the number of data-dependencies in a program, which makes it easier to exploit parallelism. The technique for generating new values is based on the paper ''On Generating Unique Names'' by Lennart Augustsson, Mikael Rittri, and Dan Synek.
This module provides a simple, efficient supply of integers using atomic fetch-and-add. To use this module, first create an IntSupply. This is often done once at the top level of an application, in global scope.
import IntSupply (IntSupply)
import IntSupply qualified
import System.IO.Unsafe (unsafePerformIO)

myIntSupply :: IntSupply
myIntSupply = unsafePerformIO IntSupply.new
{-# NOINLINE myIntSupply #-}
Next, call IntSupply.next on the supply, which will return 0, then 1, and so on.
> IntSupply.next myIntSupply
0
> IntSupply.next myIntSupply
1
If desired, you can reset the count to 0.
> IntSupply.reset myIntSupply
> IntSupply.next myIntSupply
0
On a 64-bit machine, for many applications, these integers can be treated as effectively unique: even if 1,000,000,000 integers were generated per second, it would still take over 580 years to wrap around. On a 32-bit machine, more care must be taken, of course: even if only 1,000 integers were generated per second, it would only take 50 days to wrap around.