Variants
A variant type is a type that defines a type by the union of non-overlapping cases, so a value of a variant type is either this, or that or... The simplest variant type is equivalent to the enumerated types found in Java, C++, JavaScript etc.
Here is how we define a coin as being either head or tail (and nothing else):
The names Head
and Tail
in the definition of the type coin
are
called data constructors, or variants. In this particular case,
they carry no information beyond their names, so they are called
constant constructors.
In general, it is interesting for variants to carry some information, and thus go beyond enumerated types. In the following, we show how to define different kinds of users of a system.
A constant constructor is equivalent to the same constructor taking an
argument of type unit
, so, for example, Guest()
is the same value
as Guest([])
or Guest(unit)
.
Unit
The type unit
is a predefined type that contains only one value that
carries no information. It is used when no relevant information is
required or produced.
The unique value of type unit
is []
, like an empty tuple.
Options
The option
type is a parametric, predefined variant type that is
used to express whether there is a value of some type or none. This is
especially useful when calling a partial function, that is, a
function that is not defined for some inputs. In that case, the value
of the option
type would be None()
, otherwise Some(v)
, where v
is some meaningful value of any type. A typical example from
arithmetics is the division:
Note: See the predefined namespace Option
Euclidean Division
For cases when you need both the quotient and the remainder, LIGO
provides the ediv
operation. ediv(x,y)
returns Some (quotient,
remainder)
, unless y
is zero, in which case it returns None
. The
function ediv
is overloaded to accept all the combinations (4) of
natural and integer numbers:
Checking positivity
You can check if a value is a natural number (nat
) by using a
predefined cast function which accepts an integer (int
) and returns
an optional natural number (nat
): if the result is None
, then the
given integer was positive, otherwise the corresponding natural number
n
is given with Some(n)
.
Matching
Variant types being, in essence, the disjunctive union of cases akin to types, values of such types need to be examined case by case: this is what pattern matching does.
Here is a function that transforms a colour variant type to an integer.
Note: The
when
-clauses must cover all the variants of the typecolour
. When the constructor has no argument, which is equivalent to having a[]
(unit) argument, it can be omitted, hencewhen(Default)
instead ofwhen(Default())
.
The right-hand sides of each when
-clause is an expression. Sometimes
we might need statements to be processed before a value is given to
the clause. In that case, the do
expression comes handy. It enables
the opening of a block of statements like a function body, that is, a
block ended with a return
statement whose argument has the value of
the block, like so:
Another example is matching on whether an integer is a natural number or not: