ligo/gitlab-pages/docs/language-basics/unit-option-pattern-matching.md
2020-02-05 16:28:40 +01:00

232 lines
5.5 KiB
Markdown

---
id: unit-option-pattern-matching
title: Unit, Option, Pattern matching
---
Optionals are a pervasive programing pattern in OCaml. Since Michelson
and LIGO are both inspired by OCaml, *optional types* are available in
LIGO as well. Similarly, OCaml features a *unit* type, and LIGO
features it as well. Both the option type and the unit types are
instances of a more general kind of types: *variant types* (sometimes
called *sum types*).
## The unit type
The `unit` type in Michelson or LIGO is a predefined type that
contains only one value that carries no information. It is used when
no relevant information is required or produced. Here is how it used.
> 💡 Units come in handy when we try pattern matching on custom
> variants below.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
In PascaLIGO, the unique value of the `unit` type is `Unit`.
```pascaligo group=a
const n : unit = Unit
```
<!--CameLIGO-->
In CameLIGO, the unique value of the `unit` type is `()`, following
the OCaml convention.
```cameligo group=a
let n : unit = ()
```
<!--ReasonLIGO-->
In ReasonLIGO, the unique value of the `unit` type is `()`, following
the OCaml convention.
```reasonligo group=a
let n : unit = ();
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Variant types
A variant type is a user-defined or a built-in type (in case of
options) that defines a type by 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):
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=b
type coin is Head | Tail
const head : coin = Head (Unit) // Unit needed because of a bug
const tail : coin = Tail (Unit) // Unit needed because of a bug
```
<!--CameLIGO-->
```cameligo group=b
type coin = Head | Tail
let head : coin = Head
let tail : coin = Tail
```
<!--ReasonLIGO-->
```reasonligo group=b
type coin = | Head | Tail;
let head : coin = Head;
let tail : coin = Tail;
```
<!--END_DOCUSAURUS_CODE_TABS-->
The names `Head` and `Tail` in the definition of the type `coin` are
called *data constructors*, or *variants*.
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.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=c
type id is nat
type user is
Admin of id
| Manager of id
| Guest
const u : user = Admin (1000n)
const g : user = Guest (Unit) // Unit needed because of a bug
```
<!--CameLIGO-->
```cameligo group=c
type id = nat
type user =
Admin of id
| Manager of id
| Guest
let u : user = Admin 1000n
let g : user = Guest
```
<!--ReasonLIGO-->
```reasonligo group=c
type id = nat;
type user =
| Admin (id)
| Manager (id)
| Guest;
let u : user = Admin (1000n);
let g : user = Guest;
```
<!--END_DOCUSAURUS_CODE_TABS-->
Defining a variant can be extremely useful for building semantically
appealing contracts. We will learn how to use variants for "logic
purposes"' shortly.
## Optional values
The `option` type is a 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*. An example in arithmetic is the
division operation:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=d
function div (const a : nat; const b : nat) : option (nat) is
if b = 0n then (None: option (nat)) else Some (a/b)
```
<!--CameLIGO-->
```cameligo group=d
let div (a, b : nat * nat) : nat option =
if b = 0n then (None: nat option) else Some (a/b)
```
<!--ReasonLIGO-->
```reasonligo group=d
let div = ((a, b) : (nat, nat)) : option (nat) =>
if (b == 0n) { (None: option (nat)); } else { Some (a/b); };
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Pattern matching
*Pattern matching* is similiar to the `switch` construct in
Javascript, and can be used to route the program's control flow based
on the value of a variant. Consider for example the definition of a
function `flip` that flips a coin, as defined above.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=e
type coin is Head | Tail
function flip (const c : coin) : coin is
case c of
Head -> Tail (Unit) // Unit needed because of a bug
| Tail -> Head (Unit) // Unit needed because of a bug
end
```
You can call the function `flip` by using the LIGO compiler like so:
```shell
ligo run-function
gitlab-pages/docs/language-basics/src/unit-option-pattern-matching/flip.ligo
flip "(Head (Unit))"
# Outputs: Tail(Unit)
```
<!--CameLIGO-->
```cameligo group=e
type coin = Head | Tail
let flip (c : coin) : coin =
match c with
Head -> Tail
| Tail -> Head
```
You can call the function `flip` by using the LIGO compiler like so:
```shell
ligo run-function
gitlab-pages/docs/language-basics/src/unit-option-pattern-matching/flip.mligo
flip Head
# Outputs: Tail(Unit)
```
<!--ReasonLIGO-->
```reasonligo group=e
type coin = | Head | Tail;
let flip = (c : coin) : coin =>
switch (c) {
| Head => Tail
| Tail => Head
};
```
You can call the function `flip` by using the LIGO compiler like so:
```shell
ligo run-function
gitlab-pages/docs/language-basics/src/unit-option-pattern-matching/flip.religo
flip Head
# Outputs: Tail(Unit)
```
<!--END_DOCUSAURUS_CODE_TABS-->