Many of the functions defined by this package make use of generalised comparison functions
which return a variant of the Prelude Ordering data type: Data.COrdering.COrdering. These
are refered to as "combining comparisons". (This is because they combine "equal"
values in some manner defined by the user.)

The idea is that using this simple mechanism you can define many practical and
useful variations of tree (or general set) operations from a few generic primitives,
something that would not be so easy using plain Ordering comparisons
(overloaded or otherwise).

Functions which involve searching a tree really only require a single argument
function which takes the current tree element value as argument and returns
an Ordering or Data.COrdering.COrdering to direct the next stage of the search down
the left or right sub-trees (or stop at the current element). For documentation
purposes, these functions are called "selectors" throughout this library.
Typically a selector will be obtained by partially applying the appropriate
combining comparison with the value or key being searched for. For example..

Types.

The balance factor (BF) of an AVL tree node is defined as the difference between the height of
the left and right sub-trees. An AVL tree is ALWAYS height balanced, such that |BF| <= 1.
The functions in this library (Data.Tree.AVL) are designed so that they never construct
an unbalanced tree (well that's assuming they're not broken). The AVL tree type defined here
has the BF encoded the constructors.

Some functions in this library return AVL trees that are also "flat", which (in the context
of this library) means that the sizes of left and right sub-trees differ by at most one and
are also flat. Flat sorted trees should give slightly shorter searches than sorted trees which
are merely height balanced. Whether or not flattening is worth the effort depends on the number
of times the tree will be searched and the cost of element comparison.

In cases where the tree elements are sorted, all the relevant AVL functions follow the
convention that the leftmost tree element is least and the rightmost tree element is
the greatest. Bear this in mind when defining general comparison functions. It should
also be noted that all functions in this library for sorted trees require that the tree
does not contain multiple elements which are "equal" (according to whatever criterion
has been used to sort the elements).

It is important to be consistent about argument ordering when defining general purpose
comparison functions (or selectors) for searching a sorted tree, such as ..

This convention is same as that used by the overloaded compare method from Ord class.

WARNING: The constructors of this data type are exported from this module but not from
the top level AVL wrapper (Data.Tree.AVL). Don't try to construct your own AVL
trees unless you're sure you know what your doing. If you end up creating and using
AVL trees that aren't you'll break most of the functions in this library.

Controlling Strictness.

The AVL data type is declared as non-strict in all it's fields,
but all the functions in this library behave as though it is strict in its
recursive fields (left and right sub-trees). Strictness in the element field is
controlled either by using the strict variants of functions (defined in this library
where appropriate), or using strict variants of the combinators defined in Data.COrdering,
or using seq etc. in your own code (in any combining comparisons you define, for example).

The Eq and Ord instances.

Begining with version 3.0 these are now derived, and hence are defined in terms of
strict structural equality, rather than observational equivalence. The reason for
this change is that the observational equivalence abstraction was technically breakable
with the exposed API. But since this change, some functions which were previously
considered unsafe have become safe to expose (those that measure tree height).

Fast algorithm to calculate size. This avoids visiting about 50% of tree nodes
by using fact that trees with small heights can only have particular shapes.
So it's still O(n), but with substantial saving in constant factors.

Returns the exact tree size in the form (Just n) if this is less than or
equal to the input clip value. Returns Nothing of the size is greater than
the clip value. This function exploits the same optimisation as fastAddSize.

A fast algorithm for comparing the heights of two trees. This algorithm avoids the need
to compute the heights of both trees and should offer better performance if the trees differ
significantly in height. But if you need the heights anyway it will be quicker to just evaluate
them both and compare the results.

Complexity: O(log n), where n is the size of the smaller of the two trees.

General purpose function to perform a search of a sorted tree, using the supplied selector.
This function is similar to genAssertRead, but returns a the default value (first argument) if
the search fails.

Writing to sorted trees

A general purpose function to perform a search of a tree, using the supplied selector.
If the search succeeds the found element is replaced by the value (e) of the (Eq e)
constructor returned by the selector. If the search fails this function returns the original tree.

Functionally identical to genWrite, but returns an identical tree (one with all the nodes on
the path duplicated) if the search fails. This should probably only be used if you know the
search will succeed and will return an element which is different from that already present.

A general purpose function to perform a search of a tree, using the supplied selector.
The found element is replaced by the value (e) of the (Eq e) constructor returned by
the selector. This function returns Nothing if the search failed.

Similar to genWrite, but also returns the original tree if the search succeeds but
the selector returns (EqNothing). (This version is intended to help reduce heap burn
rate if it's likely that no modification of the value is needed.)

Similar to genTryWrite, but also returns the original tree if the search succeeds but
the selector returns (EqNothing). (This version is intended to help reduce heap burn
rate if it's likely that no modification of the value is needed.)

Pushing on sorted AVL trees

General push. This function searches the AVL tree using the supplied selector. If a matching element
is found it's replaced by the value (e) returned in the (Eq e) constructor returned by the selector.
If no match is found then the default element value is added at in the appropriate position in the tree.

Note that for this to work properly requires that the selector behave as if it were comparing the
(potentially) new default element with existing tree elements, even if it isn't.

Note also that this function is non-strict in it's second argument (the default value which
is inserted if the search fails or is discarded if the search succeeds). If you want
to force evaluation, but only if it's actually incorprated in the tree, then use genPush'

Almost identical to genPush, but this version forces evaluation of the default new element
(second argument) if no matching element is found. Note that it does not do this if
a matching element is found, because in this case the default new element is discarded
anyway. Note also that it does not force evaluation of any replacement value provided by the
selector (if it returns Eq). (You have to do that yourself if that's what you want.)

Similar to genPush, but returns the original tree if the combining comparison returns
(EqNothing). So this function can be used reduce heap burn rate by avoiding duplication
of nodes on the insertion path. But it may also be marginally slower otherwise.

Note that this function is non-strict in it's second argument (the default value which
is inserted in the search fails or is discarded if the search succeeds). If you want
to force evaluation, but only if it's actually incorprated in the tree, then use genPushMaybe'

Almost identical to genPushMaybe, but this version forces evaluation of the default new element
(second argument) if no matching element is found. Note that it does not do this if
a matching element is found, because in this case the default new element is discarded
anyway.

Functionally identical to genDel, but returns an identical tree (one with all the nodes on
the path duplicated) if the search fails. This should probably only be used if you know the
search will succeed.

This version only deletes the element if the supplied selector returns (EqNothing).
If it returns (Eq (Just e)) then the matching element is replaced by e.
If no matching element is found then this function returns the original tree.

Complexity: O(log n)

"Popping" elements from AVL trees

"Popping" means reading and deleting a tree element in a single operation.

Popping from extreme left or right

Pop the left-most element from a non-empty AVL tree, returning the popped element and the
modified AVL tree. If the tree is sorted this will be the least element.
This function raises an error if it's argument is an empty tree.

Pop the right-most element from a non-empty AVL tree, returning the popped element and the
modified AVL tree. If the tree is sorted this will be the greatest element.
This function raises an error if it's argument is an empty tree.

Popping from sorted trees

General purpose function for popping elements from a sorted AVL tree.
An error is raised if a matching element is not found. The pair returned
by this function consists of the popped value and the modified tree.

In this case the selector returns two values if a search succeeds.
If the second is (Just e) then the new value (e) is substituted in the same place in the tree.
If the second is Nothing then the corresponding tree element is deleted.
This function raises an error if the search fails.

A simpler version of genAssertPopMaybe. The corresponding element is deleted if the second value
returned by the selector is True. If it's False, the original tree is returned.
This function raises an error if the search fails.

Converting Lists to AVL trees (fixed element order)

Convert a list of known length into an AVL tree, such that the head of the list becomes
the leftmost tree element. The resulting tree is flat (and also sorted if the supplied list
is sorted in ascending order).

If the actual length of the list is not the same as the supplied length then
an error will be raised.

Convert a list of known length into an AVL tree, such that the head of the list becomes
the rightmost tree element. The resulting tree is flat (and also sorted if the supplied list
is sorted in descending order).

If the actual length of the list is not the same as the supplied length then
an error will be raised.

The AVL equivalent of Data.List.mapAccumL on lists.
It behaves like a combination of mapAVL and foldlAVL.
It applies a function to each element of a tree, passing an accumulating parameter from
left to right, and returning a final value of this accumulator together with the new tree.

Using this version with a function that is strict in it's first argument will result in
O(n) stack use. See mapAccumLAVL' for a strict version.

The AVL equivalent of Data.List.mapAccumR on lists.
It behaves like a combination of mapAVL and foldrAVL.
It applies a function to each element of a tree, passing an accumulating parameter from
right to left, and returning a final value of this accumulator together with the new tree.

Using this version with a function that is strict in it's first argument will result in
O(n) stack use. See mapAccumRAVL' for a strict version.

This is a strict version of mapAccumLAVL, which is useful for functions which
are strict in their first argument. The advantage of this version is that it reduces
the stack use from the O(n) that the lazy version gives (when used with strict functions)
to O(log n).

This is a strict version of mapAccumRAVL, which is useful for functions which
are strict in their first argument. The advantage of this version is that it reduces
the stack use from the O(n) that the lazy version gives (when used with strict functions)
to O(log n).

Remove all AVL tree elements which do not satisfy the supplied predicate.
Element ordering is preserved. The resulting tree is flat.
See filterAVL for an alternative implementation which is probably more efficient.

Remove all AVL tree elements for which the supplied function returns Nothing.
Element ordering is preserved. The resulting tree is flat.
See mapMaybeAVL for an alternative implementation which is probably more efficient.

Partition an AVL tree using the supplied predicate. The first AVL tree in the
resulting pair contains all elements for which the predicate is True, the second
contains all those for which the predicate is False. Element ordering is preserved.
Both of the resulting trees are flat.

Complexity: O(n)

Folds

Note that unlike folds over lists (foldr and foldl), there is no
significant difference between left and right folds in AVL trees, other
than which side of the tree each starts with.
Therefore this library provides strict and lazy versions of both.

The AVL equivalent of foldr on lists. This is a the lazy version (as lazy as the folding function
anyway). Using this version with a function that is strict in it's second argument will result in O(n)
stack use. See foldrAVL' for a strict version.

The strict version of foldrAVL, which is useful for functions which are strict in their second
argument. The advantage of this version is that it reduces the stack use from the O(n) that the lazy
version gives (when used with strict functions) to O(log n).

The AVL equivalent of foldr1 on lists. This is a the lazy version (as lazy as the folding function
anyway). Using this version with a function that is strict in it's second argument will result in O(n)
stack use. See foldr1AVL' for a strict version.

The strict version of foldr1AVL, which is useful for functions which are strict in their second
argument. The advantage of this version is that it reduces the stack use from the O(n) that the lazy
version gives (when used with strict functions) to O(log n).

This fold is a hybrid between foldrAVL and foldr1AVL. As with foldr1AVL, it requires
a non-empty tree, but instead of treating the rightmost element as an initial value, it applies
a function to it (second function argument) and uses the result instead. This allows
a more flexible type for the main folding function (same type as that used by foldrAVL).
As with foldrAVL and foldr1AVL, this function is lazy, so it's best not to use it with functions
that are strict in their second argument. See foldr2AVL' for a strict version.

The strict version of foldr2AVL, which is useful for functions which are strict in their second
argument. The advantage of this version is that it reduces the stack use from the O(n) that the lazy
version gives (when used with strict functions) to O(log n).

The AVL equivalent of foldl on lists. This is a the lazy version (as lazy as the folding function
anyway). Using this version with a function that is strict in it's first argument will result in O(n)
stack use. See foldlAVL' for a strict version.

The strict version of foldlAVL, which is useful for functions which are strict in their first
argument. The advantage of this version is that it reduces the stack use from the O(n) that the lazy
version gives (when used with strict functions) to O(log n).

The AVL equivalent of foldl1 on lists. This is a the lazy version (as lazy as the folding function
anyway). Using this version with a function that is strict in it's first argument will result in O(n)
stack use. See foldl1AVL' for a strict version.

The strict version of foldl1AVL, which is useful for functions which are strict in their first
argument. The advantage of this version is that it reduces the stack use from the O(n) that the lazy
version gives (when used with strict functions) to O(log n).

This fold is a hybrid between foldlAVL and foldl1AVL. As with foldl1AVL, it requires
a non-empty tree, but instead of treating the leftmost element as an initial value, it applies
a function to it (second function argument) and uses the result instead. This allows
a more flexible type for the main folding function (same type as that used by foldlAVL).
As with foldlAVL and foldl1AVL, this function is lazy, so it's best not to use it with functions
that are strict in their first argument. See foldl2AVL' for a strict version.

The strict version of foldl2AVL, which is useful for functions which are strict in their first
argument. The advantage of this version is that it reduces the stack use from the O(n) that the lazy
version gives (when used with strict functions) to O(log n).

Concatenate a finite list of AVL trees. During construction of the resulting tree the
input list is consumed lazily, but it will be consumed entirely before the result is returned.

asListL (concatAVL avls) = concatMap asListL avls

Complexity: Umm..Dunno. Uses a divide and conquer approach to splice adjacent pairs of
trees in the list recursively, until only one tree remains. The complexity of each splice
is proportional to the difference in tree heights.

Similar to concatAVL, except the resulting tree is flat.
This function evaluates the entire list of trees before constructing the result.

Complexity: O(n), where n is the total number of elements in the resulting tree.

Splitting AVL trees

Taking fixed size lumps of tree

Bear in mind that the tree size (s) is not stored in the AVL data structure, but if it is
already known for other reasons then for (n > s/2) using the appropriate complementary
function with argument (s-n) will be faster.
But it's probably not worth invoking Data.Tree.AVL.Types.size for no reason other than to
exploit this optimisation (because this is O(s) anyway).

This is a simplified version of splitAtL which does not return the remaining tree.
The Int argument n (n >= 0) specifies the number of elements to take (from the left).
This function raises an error if n is negative.

If the tree size is greater than n the result is (Right l) where l contains
the leftmost n elements.

If the tree size is less than or equal to n then the result is (Left s), where s is tree size.

This is a simplified version of splitAtR which does not return the remaining tree.
The Int argument n (n >= 0) specifies the number of elements to take (from the right).
This function raises an error if n is negative.

If the tree size is greater than n the result is (Right r) where r contains
the rightmost n elements.

If the tree size is less than or equal to n then the result is (Left s), where s is tree size.

This is a simplified version of splitAtR which returns the remaining tree only (leftmost elements).
This function raises an error if n is negative.

If the tree size is greater than n the result is (Right l) where l contains
the remaining elements (l will be non-empty).

If the tree size is less than or equal to n then the result is (Left s), where s is tree size.

An empty tree will always yield a result of (Left 0).

Complexity: O(n)

Rotations

Bear in mind that the tree size (s) is not stored in the AVL data structure, but if it is
already known for other reasons then for (n > s/2) using the appropriate complementary
function with argument (s-n) will be faster.
But it's probably not worth invoking Data.Tree.AVL.Types.size for no reason other than to exploit this optimisation
(because this is O(s) anyway).

Rotate an AVL tree left by n places. If s is the size of the tree then ordinarily n
should be in the range [0..s-1]. However, this function will deliver a correct result
for any n (n<0 or n>=s), the actual rotation being given by (n `mod` s) in such cases.
The result of rotating an empty tree is an empty tree.

Rotate an AVL tree right by n places. If s is the size of the tree then ordinarily n
should be in the range [0..s-1]. However, this function will deliver a correct result
for any n (n<0 or n>=s), the actual rotation being given by (n `mod` s) in such cases.
The result of rotating an empty tree is an empty tree.

Complexity: O(n)

Taking lumps of tree according to a supplied predicate

Span an AVL tree from the left, using the supplied predicate. This function returns
a pair of trees (l,r), where l contains the leftmost consecutive elements which
satisfy the predicate. The leftmost element of r (if any) is the first to fail
the predicate. Either of the resulting trees may be empty. Element ordering is preserved.

Span an AVL tree from the right, using the supplied predicate. This function returns
a pair of trees (l,r), where r contains the rightmost consecutive elements which
satisfy the predicate. The rightmost element of l (if any) is the first to fail
the predicate. Either of the resulting trees may be empty. Element ordering is preserved.

This is a simplified version of spanL which does not return the tree containing
the elements which satisfy the supplied predicate.
The result is a tree whose leftmost element is the first to fail the predicate, starting from
the left (which may be empty).

This is a simplified version of spanR which does not return the tree containing
the elements which satisfy the supplied predicate.
The result is a tree whose rightmost element is the first to fail the predicate, starting from
the right (which may be empty).

Complexity: O(n), where n is the number of elements dropped.

Taking lumps of sorted trees

Prepare to get confused. All these functions adhere to the same Ordering convention as
is used for searches. That is, if the supplied selector returns LT that means the search
key is less than the current tree element. Or put another way, the current tree element
is greater than the search key.

So (for example) the result of the genTakeLT function is a tree containing all those elements
which are less than the notional search key. That is, all those elements for which the
supplied selector returns GT (not LT as you might expect). I know that seems backwards, but
it's consistent if you think about it.

Divide a sorted AVL tree into left and right sorted trees (l,r), such that l contains all the
elements less than or equal to according to the supplied selector and r contains all the elements greater than
according to the supplied selector.

Divide a sorted AVL tree into left and right sorted trees (l,r), such that l contains all the
elements less than supplied selector and r contains all the elements greater than or equal to the
supplied selector.

This is a simplified version of genForkL which returns a sorted tree containing
only those elements which are less than or equal to according to the supplied selector.
This function also has the synonym genDropGT.

This is a simplified version of genForkR which returns a sorted tree containing
only those elements which are less than according to the supplied selector.
This function also has the synonym genDropGE.

This is a simplified version of genForkR which returns a sorted tree containing
only those elements which are greater or equal to according to the supplied selector.
This function also has the synonym genDropLT.

Set operations

Functions for manipulating AVL trees which represent ordered sets (I.E. sorted trees).
Note that although many of these functions work with a variety of different element
types they all require that elements are sorted according to the same criterion (such
as a field value in a record).

Union

Uses the supplied combining comparison to evaluate the union of two sets represented as
sorted AVL trees. Whenever the combining comparison is applied, the first comparison argument is
an element of the first tree and the second comparison argument is an element of the second tree.

Complexity: Not sure, but I'd appreciate it if someone could figure it out.
(Faster than Hedge union from Data.Set at any rate).

Similar to genIntersection, but the resulting tree does not include elements in cases where
the supplied combining comparison returns (Eq Nothing).

Complexity: Not sure, but I'd appreciate it if someone could figure it out.

Intersection with the result as a list

Sometimes you don't want intersection to give a tree, particularly if the
resulting elements are not orderered or sorted according to whatever criterion was
used to sort the elements of the input sets.

The reason these variants are provided for intersection only (and not the other
set functions) is that the (tree returning) intersections always construct an entirely
new tree, whereas with the others the resulting tree will typically share sub-trees
with one or both of the originals. (Of course the results of the others can easily be
converted to a list too if required.)

Subset

Uses the supplied comparison to test whether the first set is a subset of the second,
both sets being represented as sorted AVL trees. This function returns True if any of
the following conditions hold..

The first set is empty (the empty set is a subset of any set).

The two sets are equal.

The first set is a proper subset of the second set.

Complexity: Not sure, but I'd appreciate it if someone could figure it out.

Similar to genIsSubsetOf, but also requires that the supplied combining
comparison returns (Eq True) for matching elements.

Complexity: Not sure, but I'd appreciate it if someone could figure it out.

The AVL Zipper

An implementation of "The Zipper" for AVL trees. This can be used like
a functional pointer to a serial data structure which can be navigated
and modified, without having to worry about all those tricky tree balancing
issues. See JFP Vol.7 part 5 or ..

The functions defined here provide a useful way to achieve those awkward
operations which may not be covered by the rest of this package. They're
reasonably efficient (mostly O(log n) or better), but zipper flexibility
is bought at the expense of keeping path information explicitly as a heap
data structure rather than implicitly on the stack. Since heap storage
probably costs more, zipper operations will are likely to incur higher
constant factors than equivalent non-zipper operations (if available).

Some of the functions provided here may appear to be weird combinations of
functions from a more logical set of primitives. They are provided because
they are not really simple combinations of the corresponding primitives.
They are more efficient, so you should use them if possible (e.g combining
deleting with Zipper closing).

Also, consider using the BAVL as a cheaper alternative if you don't
need to navigate the tree.

Types

Abstract data type for an unsuccessfully opened AVL tree.
A PAVL can be thought of as a functional pointer to the gap
where the expected element should be (but isn't). You can fill this gap using
the fill function, or fill and close at the same time using the fillClose function.

Attempts to open a sorted AVL tree at the element given by the supplied selector.
This function returns Nothing if there is no such element.

Note that this operation will still create a zipper path structure on the heap (which
is promptly discarded) if the search fails, and so is potentially inefficient if failure
is likely. In cases like this it may be better to use genOpenBAVL, test for "fullness"
using fullBAVL and then convert to a ZAVL using fullBAVLtoZAVL.

Attempts to open a sorted AVL tree at the greatest element which is less than or equal, according to
the supplied selector. This function returns _Nothing_ if the tree does not contain such an element.

Fill the gap pointed to by a PAVL with the supplied element, which becomes
the current element of the resulting ZAVL. The supplied filling element should
be "equal" to the value used in the search which created the PAVL.

Operations on whole zippers

A cheaper option is to use BAVL

These are a cheaper but more restrictive alternative to using the full Zipper.
They use "Binary Paths" (Ints) to point to a particular element of an AVL tree.
Use these when you don't need to navigate the tree, you just want to look at a
particular element (and perhaps modify or delete it). The advantage of these is
that they don't create the usual Zipper heap structure, so they will be faster
(and reduce heap burn rate too).

If you subsequently decide you need a Zipper rather than a BAVL then some conversion
utilities are provided.

Types

A BAVL is like a pointer reference to somewhere inside an AVL tree. It may be either "full"
(meaning it points to an actual tree node containing an element), or "empty" (meaning it
points to the position in a tree where an element was expected but wasn't found).

Modifying the tree

If the BAVL is "full", this function returns the original tree with the corresponding
element replaced by the new element (first argument). If it's "empty" the original tree is returned
with the new element inserted.

Converting to BAVL to Zipper

These are O(log n) operations but with low constant factors because no comparisons
are required (and the tree nodes on the path will most likely still be in cache as
a result of opening the BAVL in the first place).

Inserts a new tree element. Assumes the path bits were extracted from a EmptyBP constructor.
This function replaces the first Empty node it encounters with the supplied value, regardless
of the current path bits (which are not checked). DO NOT USE THIS FOR REPLACING ELEMENTS ALREADY
PRESENT IN THE TREE (use writePath for this).