Contents

1 Unboxed references

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

Unboxed references can contain only values of following types:
Bool, Char, Int, Int8..Int64, Word, Word8..Word64, Float, Double,
Ptr a, FunPtr a, StablePtr a. These types are members of Unboxed class
and you can implement new instances of this class by converting values
of some other type (say, CChar) to values of 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 what allows to simplify
debugging of programs that uses them. Please note that unboxed references
always hold computed values, in contrast to boxed references, that can
contain unevaluated thunk.

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

2 Monad-independent references

Sometimes you need to write code that will be compatible both with IO
and ST monads, and even better with any monad that has 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 type of usage - readArray and writeArray can work
in any monad. But it's not true for references - you need to use
readIORef for IO monad, but readSTRef for ST monad, so if you need to
implement 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 both in IO and 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 similar way with operations newURef, readURef, writeURef.

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

3 Syntax sugar for mutable types

Haskell don't support convenient syntax for using mutable vars, such
as references, arrays and hash tables. The library includes module
that partially simplifies their usage. For example:

Basically, the module supports syntax 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

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

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

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

- Some operations can be slower with new implementation because i'm
not sure that i discovered all the clever tricks used in original lib.
Please test speed and report me about any problems

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

because `bounds` operation is part of HasBounds class that is no more
base class for MArray. That you can do to fix this problem? Either:

- Add 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 old and new
versions of Arrays library, but it will work only with "old" mutable
arrays and don't support dynamic arrays.

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

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

I should mention that despite MArray now don't based on the HasBounds
class, all the old mutable array types (IOArray..StorableArray) still
implements 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:

4.2 Using dynamic (resizable) arrays

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

Dynamic array can be resized explicitly by resizeDynamicArray operation:

resizeDynamicArray array (l,u)

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

To create array that will be automatically resized on attempt to write
beyond current bounds, you should use newDynamicArray or
newDynamicArray_ operation (former initialize array to given initial
value while later leave array uninitialized). Their first argument
determine array expansion policy:

This array will grow at least two times each time when automatic
expansion occurs, what is determined by using the `growTwoTimes`
parameter. This parameter is just the ordinary function what 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
policy himself, or use one of premastered ones:

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

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

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

And now about types of dynamic arrays. These types reflect all the
types you can use for mutable arrays, and includes DynamicIOArray,
DynamicIOUArray, DynamicSTArray, DynamicSTUArray, that has just the
same parameters as corresponding arrays without "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 IO monad:

DynamicIO StorableArray IntDouble

or 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.