A user-defined data type is introduced with thetype
keyword and a modifierunique
orstructural
.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 namedOptional
),followed by names for any type arguments (here there is one and it’s calleda
).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 constructionOptional Nat
is a type, whereasOptional
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 areNone
andSome
),followed by thetypesof the arguments to the constructor.
When Unison compiles a type definition, it generates a term for each data constructor. Here they are the termsSome : a -> Optional a
,andNone : Optional a
.It also generatespatternsfor matching on data (seePattern Matching).
Note that these terms and patterns receive qualified names: if the type namedx.y.Z
has a data constructorC
,the generated term and pattern forC
will be namedx.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