Authors: *Richard A. O'Keefe, L.Damas, V.S.Costa and Markus
Triska*

An *association list* as implemented by this library is a
collection of unique *keys* that are associated to *values*.
Keys must be ground, values need not be.

An association list can be used to *fetch* elements via their
keys and to *enumerate* its elements in ascending order of their
keys.

This library uses **AVL trees** to implement association lists.
This means that

- inserting a key
- changing an association
- fetching a single element

are all *O(*`log(N)`

) *worst-case* (and
expected) time operations, where
*N* denotes the number of elements in the association list.

The logarithmic overhead is often acceptable in practice. Notable
advantages of association lists over several other methods are:

`library(assoc)`

is written entirely in Prolog, making it
portable to other systems
- the interface predicates fit the declarative nature of Prolog,
avoiding destructive updates to terms
- AVL trees scale very predictably and can be used to represent sparse
arrays efficiently.

An association list is *created* with one of the following
predicates:

- [semidet]
**empty_assoc**(`?Assoc`) - Is true if
`Assoc` is the empty association list.
- [det]
**list_to_assoc**(`+Pairs,
-Assoc`) - Create an association from a list
`Pairs` of Key-Value pairs.
List must not contain duplicate keys.
- Errors
`domain_error(unique_key_pairs, List)`

if List contains
duplicate keys

- [det]
**ord_list_to_assoc**(`+Pairs,
-Assoc`) `Assoc` is created from an ordered list `Pairs` of
Key-Value pairs. The pairs must occur in strictly ascending order of
their keys.
- Errors
`domain_error(key_ordered_pairs, List)`

if pairs are not
ordered.

An association list can be *queried* with:

- [semidet]
**get_assoc**(`+Key,
+Assoc, -Value`) - True if
`Key`-`Value` is an association in `Assoc`.
- [semidet]
**get_assoc**(`+Key,
+Assoc0, ?Val0, ?Assoc, ?Val`) - True if
`Key`-`Val0` is in `Assoc0` and `Key`-`Val`
is in `Assoc`.
- [semidet]
**max_assoc**(`+Assoc,
-Key, -Value`) - True if
`Key`-`Value` is in `Assoc` and `Key`
is the largest key.
- [semidet]
**min_assoc**(`+Assoc,
-Key, -Value`) - True if
`Key`-`Value` is in assoc and `Key`
is the smallest key.
- [nondet]
**gen_assoc**(`?Key,
+Assoc, ?Value`) - True if
`Key`-`Value` is an association in `Assoc`.
Enumerates keys in ascending order on backtracking.
- See also
- get_assoc/3.

Elements of an association list can be changed and inserted with:

- [det]
**put_assoc**(`+Key,
+Assoc0, +Value, -Assoc`) `Assoc` is `Assoc0`, except that `Key` is
associated with `Value`. This can be used to insert and change
associations.
- [semidet]
**del_assoc**(`+Key,
+Assoc0, ?Value, -Assoc`) - True if
`Key`-`Value` is in `Assoc0`. `Assoc`
is `Assoc0` with
`Key`-`Value` removed.
- [semidet]
**del_min_assoc**(`+Assoc0,
?Key, ?Val, -Assoc`) - True if
`Key`-Value is in `Assoc0` and `Key`
is the smallest key. `Assoc` is
`Assoc0` with `Key`-Value removed. Warning: This will
succeed with *no* bindings for `Key` or `Val` if `Assoc0`
is empty.
- [semidet]
**del_max_assoc**(`+Assoc0,
?Key, ?Val, -Assoc`) - True if
`Key`-Value is in `Assoc0` and `Key`
is the greatest key. `Assoc` is
`Assoc0` with `Key`-Value removed. Warning: This will
succeed with *no* bindings for `Key` or `Val` if `Assoc0`
is empty.

Conversion of (parts of) an association list to *lists* is
possible with:

- [det]
**assoc_to_list**(`+Assoc,
-Pairs`) - Translate
`Assoc` to a list `Pairs` of Key-Value
pairs. The keys in
`Pairs` are sorted in ascending order.
- [det]
**assoc_to_keys**(`+Assoc,
-Keys`) - True if
`Keys` is the list of keys in `Assoc`. The
keys are sorted in ascending order.
- [det]
**assoc_to_values**(`+Assoc,
-Values`) - True if
`Values` is the list of values in `Assoc`. `Values`
are ordered in ascending order of the key to which they were associated. `Values`
may contain duplicates.

Further inspection predicates of an association list and its elements
are:

- [semidet]
**is_assoc**(`+Assoc`) - True if
`Assoc` is an association list. This predicate checks
that the structure is valid, elements are in order, and tree is balanced
to the extent guaranteed by AVL trees. I.e., branches of each subtree
differ in depth by at most 1. Does *not* validate that keys are
sufficiently instantiated to ensure the tree remains valid if a key is
further instantiated.
- [semidet]
**map_assoc**(`:Pred,
+Assoc`) - True if
`Pred`(Value) is true for all values in `Assoc`.
- [semidet]
**map_assoc**(`:Pred,
+Assoc0, ?Assoc`) - Map corresponding values. True if
`Assoc` is `Assoc0`
with `Pred` applied to all corresponding pairs of of values.