This substitutes the numerous "fast mutable Ints", "fast mutable
Bools" and "fast mutable Ptrs" ghc-specific modules that are used in
almost any large project. In contrast to them, this library mimics
the well-known interface of IORef/STRef:

Unboxed references for the IO monad have the type "IOURef a" and operations
newIOURef, readIOURef, writeIOURef. Unboxed references for the ST monad
have the type "STURef s a" and operations newSTURef, readSTURef,
writeSTURef.

Unboxed references can only contain values of the following types:
Bool, Char, Int, Int8..Int64, Word, Word8..Word64, Float, Double,
Ptr a, FunPtr a, StablePtr a. These types are members of the Unboxed class
and you can implement new instances of this class by converting values
of some other type (say, CChar) to values of an already supported type.

Despite all these improvements, operations with unboxed references are
compiled to the same code as for any "fast mutable variables". Moreover,
unboxed references are available even for Hugs, which allows simplified
debugging of programs that use them. Please note that unboxed references
always hold computed values, in contrast to boxed references, which can
contain unevaluated thunks.

I wish to thank Simon Marlow and especially Oleg Kiselyov who proposed
the idea of these references and their implementation (in particular, see
[1])

You can find examples of using unboxed references in "Examples/URef.hs"

Sometimes you need to write code that will be compatible with both IO
and ST monads, and even better with any monad that is lifted from
one of these two. This is especially useful for writing library code that
should be as generic as possible. Operations for arrays, for example,
are ready for such a kind of usage - readArray and writeArray can work
in any monad. But this is not true for references - you need to use
readIORef for the IO monad, but readSTRef for the ST monad, so if you need to
implement a monad-independent algorithm that uses references, you will
be in trouble. This module solves this problem by providing
monad-independent operations on boxed and unboxed references. So, the
following routine:

test_Ref =do x <- newRef (0::Int)
writeRef x 1
readRef x

can be executed in both the IO and the ST monads:

main =do a <- test_Ref
print a
let b = runST test_Ref
print b

This example uses the boxed references; unboxed references can be used
in a similar way with operations newURef, readURef, writeURef.

You can find examples of writing monad-independent routines in
"Examples/Universal.hs". Another library of mine, Library/Streams, widely uses this
facility to implement common functionality for streams working in
different monads.

Basically, the module supports syntactic sugar for using the following
data types: all types of references, arrays and hash tables. Also, it
includes two operations to creating references - ref (=newRef) and
uref (=newURef). Other operations include

The library also includes modified implementations of Data.Array.*
modules. The main benefit of these modifications is a simplified internal
library structure

Nevertheless, it also includes a few user-visible changes:

- Unboxed arrays now can be used in polymorphic functions, they are defined
for every element type that belongs to the classes Unboxed and HasDefaultValue
(see also [2]).
You can add new instances to these classes

- The MArray class now supports arrays with dynamic bounds. It includes
monadic operation getBounds, and if you change your code to use
this operation with mutable arrays instead of `bounds`, your code will also
be ready to work with dynamic (resizable) arrays

- Support for dynamic (resizable) arrays is included. Their bounds can be
changed either explicitly (by `resizeDynamicArray`) or implicitly (by
writing to a non-existing position). The policy of automatic array expansion
is selected (or disabled) on array creation.

- Unboxed arrays of Bool values occupy one byte per element (in the old
implementation they used one bit per element)

- Some operations may be slower in the new implementation, because I'm
not sure that I discovered all the clever tricks used in the original library.
Please test speed and report me about any problems

In other aspects, the new arrays are equivalent to the old ones.
Just change "Array" to "ArrayBZ" in your import statements and
enjoy! :) Directory "Examples/Array" contains demonstrations of using
each array type

because the `bounds` operation is part of HasBounds class, that is no longer a
base class for MArray. What can you do to fix this problem? Either:

- Add a HasBounds restriction to the operation type:

arrayHead ::(MArray a e m, HasBounds a, Ix i)=> a i e -> m e

This way, your code will become compatible with both the old and the new
versions of the Arrays library, but it will work only with "old" mutable
arrays and won't support dynamic arrays.

- Replace calls to the `bounds` operation with calls to `getBounds`. This
way, your function will become compatible with any instance of the MArray
class, including dynamic arrays:

arrayHead marr =do(l,_)<- getBounds marr
readArray marr l

I should mention that, despite the fact that MArray isn't based on the HasBounds
class anymore, all the old mutable array types (IOArray..StorableArray) still
implement this interface. Only the new dynamic arrays don't implement
it because this is impossible. So, you can use the `bounds` operation
in code that works with one of "old" array constructors:

Just to let you know - the current implementation of dynamic arrays is
very trivial: it just saves a reference (IORef or STRef) to the mutable
array. When a dynamic array is resized, a new mutable array is allocated and the
contents is copied. New elements are filled with the same default value as when
the array was created with the newArray
or newDynamicArray operation. If a dynamic array is created with
newArray_ or newDynamicArray_, then new elements will be left
undefined.

A dynamic array can be resized explicitly by the resizeDynamicArray operation:

resizeDynamicArray array (l,u)

where (l,u) are new array bounds. If the dynamic array was created
by a newArray or newArray_ operation, it is the only way to resize it -
attempts to write beyond current bounds will raise an exception:

To create an array that will be automatically resized on attempt to write
beyond current bounds, you should use a newDynamicArray or
newDynamicArray_ operation (the former initializes an array with a given value,
while the latter leaves the array uninitialized). Their first argument
determines the array expansion policy:

This array will grow to at least two times its current size, each time automatic
expansion occurs, which is determined by using the `growTwoTimes`
parameter. This parameter is just an ordinary function that has the
following type:

type GrowBoundsF i =(i,i)-> i ->(i,i)

This function accepts old array bounds and offending index and
returns new array bounds. You can write new functions for expansion
policies yourself, or use one of predefined ones:

growTwoTimes - expand array to at least two times its current size
growMinimally - minimal growth that ensures inclusion of new index
noGrow - disable automatic growth. This policy is used for arrays created by newArray or newArray_

Please note that not every array can work with every expansion policy
and that is why I supported freedom of selection of this policy. Only
the noGrow policy is compatible with every index type. The growMinimally
policy by its type is compatible with any index, but it will not work
for partially ordered indexes, in particular for multi-dimensional
arrays. Imagine, for example, an array with the bounds (0,0)..(9,9). When you
try to write to index (15,5), this expansion policy function will
be unable to determine what the new bounds should be (0,0)..(15,9). So you
should always provide a custom expansion policy function for partially
ordered indexes. At last, the growTwoTimes policy is compatible only with
indexes belonging to class Num, but it is the most useful policy of all,
because it ensures that the program will not spend all its
time expanding arrays. On the other hand, you can provide your own
policy function that will, for example, expand an array only 1.5 times.

Dynamic arrays support the same MArray and HasMutableBounds interfaces
as other mutable arrays, but they don't support the HasBounds interface.

And now about types of dynamic arrays. These types reflect all the
types you can use for mutable arrays, and include DynamicIOArray,
DynamicIOUArray, DynamicSTArray, DynamicSTUArray, which have the
same parameters as corresponding arrays without the "Dynamic" prefix.
Some examples are:

DynamicIOArray IntDouble
DynamicSTUArray s (Int,Int)Bool

You can also create dynamic arrays from other mutable array types
working in the IO monad:

DynamicIO StorableArray IntDouble

or the ST monad:

DynamicST s (STUArray s)(Int,Int)Bool

or any other monad (ask me if you need this). Btw, implementation of
dynamic arrays use the monad-independent references class mentioned
above.

See "Examples/Array/Dynamic.hs" for further examples on using these arrays.

This wiki page is official library documentation.
Please continue to improve it and add more information about using the library.
Feel free to ask me about library usage via email:
Bulat.Ziganshin@gmail.com