Sets
Sets are unordered collections of values of the same type, like lists are ordered collections. Like the mathematical sets and lists, sets can be empty and, if not, elements of sets in LIGO are unique, whereas they can be repeated in a list.
Like lists, the type of sets is parameterised over the type of its elements. Like list elements, set elements must all have the same type.
The empty set is denoted by the predefined value Set.empty
. A
non-empty set can be built by using the function Set.literal
which
takes a list of literal elements and returns a set containing them,
and only them.
Note: The element
2
is repeated in the list, but not in the set made from it.
Note: See the predefined namespace Set
If you want to build a big set from an arbitrary list of arbitrary
values (not just literal values), then you must use Set.of_list
instead of Set.literal
:
Set elements are internally sorted by increasing values, so the type of the elements must be comparable, that is, they obey a total order (any two elements can be compared).
Sizing
The predefined functions Set.size
and Set.cardinal
return the
number of elements in a given set.
Note: See the predefined namespace Set
Searching
The predicate Set.mem
tests for membership in a given set.
Note: See the predefined namespace Set
Adding
Adding an element to a set is done by calling the function
Set.add
. If the element was already present in the given set, the
resulting set is the same as the original one.
Note: See the predefined namespace Set
Removing
The function Set.remove
creates a set containing the elements of a
given set, without a given element. If the element is not already
present, the new set is the same as the old one, as expected.
Note: See the predefined namespace Set
Updating
Previous sections show how to add and remove an element from a given
set. The function Set.update
can do both depending on a boolean
value: if true, then the given value will be added to the set,
otherwise it will be removed (if present).
The function Set.update
implements a one-value update. Sometime we
would like to provide a function that is applied in turn to all the
elements of the set, and specifies whether the element at hand has to
be discarded or replaced by a computed value. This is what
Set.filter_map
does.
As an example, let us consider a function that removes all the even numbers from a set.
Note: See the predefined namespace Set
Folding
A functional iterator is a function that traverses a data structure and calls in turn a given function over the elements of that structure to compute some value. Another approach is sometimes possible: loops.
There are three kinds of functional iterations over sets: the fold, the map (not to be confused with the map data structure) and the iteration.
Let us consider first here the fold, which is the most general form of functional iteration. The folded function takes two arguments: an accumulator and the structure element at hand, with which it then produces a new accumulator. This enables having a partial result that becomes complete when the traversal of the data structure is over.
The function Set.fold
performs a fold over a set, in increasing
order of its elements. The function Set.fold_desc
folds in
decreasing order. The different in their types is the type of the
folded operation: with Set.fold
, that function takes the accumulator
first, whereas with Set.fold_desc
, the accumulator comes second.
Note: See the predefined namespace Set
Mapping
We may want to change all the elements of a given set by applying to
them a function. This is called a map operation, not to be confused
with the map data structure. The predefined functional iterator
implementing the mapped operation over sets is called Set.map
and is
used as follows.
Note: See the predefined namespace Set
Iterating
An iterated operation is a fold over a set that returns the value of
type unit
, that is, its only use is to produce side-effects. This
can be useful if, for example, you would like to check that each
element of a set is within a certain range, and fail with an error
otherwise.
The predefined functional iterator implementing the iterated operation
over sets is called Set.iter
. In the following example, a set is
iterated to check that all its elements (integers) are greater than
3
.
Note: See the predefined namespace Set
Looping
One can iterate through all the elements of a set, in increasing
order, thanks to a loop of the form for (const <variable> of <set>) <block>
. It means that the <block>
of statements (or a single
statement) will be computed once for each <variable>
ranging over the
elements of the set <set>
in increasing order.
Here is an example where the integers in a set are summed up.
Note: See the predefined namespace Set