## Enums

### Enumerated Types

Enumerated types are used to define a type that has a finite (enumerated) set of values. Enumerated types are useful for things such as modeling compass directions, the cards in a deck, and the days in a week.

For example, here is an enumeration of the days in a week:

```
enum Weekday {
case Monday,
case Tuesday,
case Wednesday,
case Thursday,
case Friday,
case Saturday,
case Sunday
}
```

Here `Monday`

, `Tuesday`

and so on are referred to as
the *constructors* of the enum.

We can refer to a weekday as `Monday`

or
`Weekday.Monday`

.
The latter is required if we have multiple enums in
scope with similarly named constructors.

We can use pattern matching to destruct an enum value. For example:

```
enum Animal {
case Cat,
case Dog,
case Giraffe
}
def isTall(a: Animal): Bool = match a {
case Cat => false
case Dog => false
case Giraffe => true
}
```

The function `isTall`

takes a value of type `Animal`

and performs a pattern match on it.
If the value is `Giraffe`

the function returns
`true`

.
Otherwise it returns `false`

.

Flix guarantees that pattern matches are exhaustive,
i.e. that all cases have been covered.
It is a compile-time error if a pattern match is
non-exhaustive.
A pattern match can always be made exhaustive by
adding a default case as the last case.
A default case is written with an underscore
`case _ => ???`

.

### Recursive Types

Recursive types are used to define types that are self-referential.

For example, we can define a binary tree of integers as follows:

```
enum Tree {
case Leaf(Int32),
case Node(Tree, Tree)
}
```

A tree is either a `Leaf`

with an `Int32`

value or an
internal `Node`

with a left and a right sub-tree.
Note that the definition of `Tree`

refers to itself.

We can write a function, using pattern matching, to compute the sum of all integers in such a tree:

```
def sum(t: Tree): Int32 = match t {
case Leaf(x) => x
case Node(l, r) => sum(l) + sum(r)
}
```

The `sum`

function pattern matches on a tree value.
If the tree is a leaf its value is simply returned.
Otherwise the function recurses on both subtrees and
adds their results.

### Polymorphic Types

Polymorphic types are types parameterized by other types. For example, we can write:

```
enum Bottle[a] {
case Empty,
case Full(a)
}
def isEmpty[a](b: Bottle[a]): Bool = match b {
case Empty => true
case Full(_) => false
}
```

Here the `Bottle`

type is parameterized by the type
parameter `a`

.
In Flix, type parameters, like ordinary parameters
are always written in lowercase.
The `Bottle`

type has two cases: either the bottle
is empty (and contains no value) or it is full (and
contains one value of type `a`

).
The `isEmpty`

function takes a bottle, type
parameterized by `a`

, and determines if the bottle
is empty.

The careful reader might have noticed that `Bottle`

is equivalent to the more well-known `Option`

type.

In general, polymorphic types can have more than one
type argument.
For example, the standard library implement of the
`Result`

has two type parameters:

```
enum Result[e, t] {
case Ok(t),
case Err(e)
}
```

### Shorthand Enum Syntax

A typical enum may look like:

```
enum Weekday {
case Monday,
case Tuesday,
case Wednesday,
case Thursday,
case Friday,
case Saturday,
case Sunday
}
```

The same enum can also be declared as:

```
enum Weekday {
case Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}
```

This shorthand syntax is always available, but should only be used for simple enums.

### Singleton Enum Syntax

An enum with a single case:

```
enum USD {
case USD(Int32)
}
```

can be shortened to:

```
enum USD(Int32)
```