Tuples, Lists, Sets
Apart from complex data types such as maps
and records
, LIGO also
features tuples
, lists
and sets
.
#
TuplesTuples gather a given number of values in a specific order and those
values, called components, can be retrieved by their index
(position). Probably the most common tuple is the pair. For
example, if we were storing coordinates on a two dimensional grid we
might use a pair (x,y)
to store the coordinates x
and y
. There
is a specific order, so (y,x)
is not equal to (x,y)
in
general. The number of components is part of the type of a tuple, so,
for example, we cannot add an extra component to a pair and obtain a
triple of the same type: (x,y)
has always a different type from
(x,y,z)
, whereas (y,x)
might have the same type as (x,y)
.
Like records, tuple components can be of arbitrary types.
#
Defining TuplesUnlike a record, tuple types do not have to be defined before they can be used. However below we will give them names by type aliasing.
#
Accessing ComponentsAccessing the components of a tuple in OCaml is achieved by
pattern matching. LIGO
currently supports tuple patterns only in the parameters of functions,
not in pattern matching. However, we can access components by their
position in their tuple, which cannot be done in OCaml. Tuple
components are zero-indexed, that is, the first component has index
0
.
#
ListsLists are linear collections of elements of the same type. Linear means that, in order to reach an element in a list, we must visit all the elements before (sequential access). Elements can be repeated, as only their order in the collection matters. The first element is called the head, and the sub-list after the head is called the tail. For those familiar with algorithmic data structure, you can think of a list a stack, where the top is written on the left.
๐ก Lists are needed when returning operations from a smart contract's main function.
#
Defining Lists#
Adding to ListsLists can be augmented by adding an element before the head (or, in terms of stack, by pushing an element on top). This operation is usually called consing in functional languages.
In PascaLIGO, the cons operator is infix and noted #
. It is not
symmetric: on the left lies the element to cons, and, on the right, a
list on which to cons. (The symbol is helpfully asymmetric to remind
you of that.)
#
Accessing list elementYou cannot access element directly in list but you can access the first element, the head or the rest of the list, the tail.
The two function to access those are List.head_opt
and List.tail_opt
#
Functional Iteration over ListsA 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 possible in PascaLIGO: loops (see the relevant section).
There are three kinds of functional iterations over LIGO lists: the iterated operation, the map operation (not to be confused with the map data structure) and the fold operation.
#
Iterated Operation over ListsThe first, the iterated operation, is an iteration over the list with a unit return value. It is useful to enforce certain invariants on the element of a list, or fail.
For example you might want to check that each value inside of a list
is within a certain range, and fail otherwise. The predefined
functional iterator implementing the iterated operation over lists is
called List.iter
.
In the following example, a list is iterated to check that all its
elements (integers) are strictly greater than 3
.
Note that
list_iter
is deprecated.
#
Mapped Operation over ListsWe may want to change all the elements of a given list 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 lists is called List.map
and
is used as follows.
Note that
list_map
is deprecated.
#
Folded Operation over ListsA folded operation is the most general of iterations. 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 predefined functional
iterator implementing the folded operation over lists is called
List.fold
and is used as follows.
Note that
list_fold
is deprecated.
#
SetsSets 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.
#
Empty SetsIn PascaLIGO, the notation for sets is similar to that for lists,
except the keyword set
is used before:
#
Non-empty SetsIn PascaLIGO, the notation for sets is similar to that for lists,
except the keyword set
is used before:
You can check that 2
is not repeated in my_set
by using the LIGO
compiler like this (the output will sort the elements of the set, but
that order is not significant for the compiler):
#
Set MembershipPascaLIGO features a special keyword contains
that operates like an
infix operator checking membership in a set.
#
Cardinal of SetsThe predefined function Set.size
returns the number of
elements in a given set as follows.
Note that
size
is deprecated.
#
Updating SetsThere are two ways to update a set, that is to add or remove from it.
In PascaLIGO, either we create a new set from the given one, or we modify it in-place. First, let us consider the former way:
Note that
set_add
andset_remove
are deprecated.
If we are in a block, we can use an instruction to modify the set bound to a given variable. This is called a patch. It is only possible to add elements by means of a patch, not remove any: it is the union of two sets.
In the following example, the parameter set s
of function update
is augmented (as the with s
shows) to include 4
and 7
, that is,
this instruction is equivalent to perform the union of two sets, one
that is modified in-place, and the other given as a literal
(extensional definition).
#
Functional Iteration over SetsA 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 possible in PascaLIGO: loops (see the relevant section).
There are three kinds of functional iterations over LIGO maps: the iterated operation, the mapped operation (not to be confused with the map data structure) and the folded operation.
#
Iterated OperationThe first, the iterated operation, is an iteration over the map with no return value: its only use is to produce side-effects. This can be useful if for example you would like to check that each value inside of a map 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 that
set_iter
is deprecated.
#
Folded OperationA folded operation is the most general of iterations. 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 predefined fold over sets
is called Set.fold
.
Note that
set_fold
is deprecated.
It is possible to use a loop over a set as well.