A user-defined data type is introduced with the`type`

keyword and a modifier`unique`

or`structural`

.The modifier indicates if the type is unique by its name, or if it is unique only by its structure. (SeeTypesfor an informal description of Unison's type system.)

For example:

or

The`=`

sign splits the definition into aleft-hand sideand aright-hand side,much like term definitions.

The left-hand side is the data type being defined. It gives a name for the data type and declares a newtype constructorwith that name (here it's named`Optional`

),followed by names for any type arguments (here there is one and it’s called`a`

).These names are bound as type variables in the right-hand side. The right-hand side may also refer to the name given to the type in the left-hand side, in which case it is a recursive type declaration. Note that the fully saturated type construction`Optional Nat`

is a type, whereas`Optional`

by itself is a type constructor, not a type (it requires a type argument in order to construct a type).

The right-hand side consists of zero or more data constructors separated by`|`

.These aredata constructorsfor the type, or ways in which values of the type can be constructed. Each case declares a name for a data constructor (here the data constructors are`None`

and`Some`

),followed by the**types**of the arguments to the constructor.

When Unison compiles a type definition, it generates a term for each data constructor. Here they are the terms`Some : a -> Optional a`

,and`None : Optional a`

.It also generatespatternsfor matching on data (seePattern Matching).

Note that these terms and patterns receive qualified names: if the type named`x.y.Z`

has a data constructor`C`

,the generated term and pattern for`C`

will be named`x.y.Z.C`

.

The general form of a type declaration is as follows:

```
<unique|structural<[<regular-identifier>]?>?> type TypeConstructor p1 p2 … pn
= DataConstructor_1
| DataConstructor_2
..
| DataConstructor_n
```