State variables are references in the IO monad, like IORefs or parts of
the OpenGL state. Note that state variables are not neccessarily writable or
readable, they may come in read-only or write-only flavours, too. As a very
simple example for a state variable, consider an explicitly allocated memory
buffer. This buffer could easily be converted into a StateVar:
makeStateVarFromPtr :: Storable a => Ptr a -> StateVar a
makeStateVarFromPtr p = makeStateVar (peek p) (poke p)
The example below puts 11 into a state variable (i.e. into the buffer),
increments the contents of the state variable by 22, and finally prints the
resulting content:
do p <- malloc :: IO (Ptr Int)
let v = makeStateVarFromPtr p
v $= 11
v $~ (+ 22)
x <- get v
print x
However, Ptr can be used directly through the same API:
do p <- malloc :: IO (Ptr Int)
p $= 11
p $~ (+ 22)
x <- get p
print x
IORefs are state variables, too, so an example with them looks extremely
similiar:
do v <- newIORef (0 :: Int)
v $= 11
v $~ (+ 22)
x <- get v
print x
A concrete implementation of a readable and writable state variable,
carrying one IO action to read the value and another IO action to write the
new value. This data type represents a piece of mutable, imperative state
with possible side-effects. These tend to encapsulate all sorts tricky
behavior in external libraries, and may well throw exceptions. Inhabitants
should satsify the following properties:
In the absence of concurrent mutation from other threads or a thrown
exception: