User-defined data types

A user-defined data type is introduced with thetypekeyword and a modifieruniqueorstructural.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:

structural type Optional a
structural type Optional a
  = lib.base.Optional.Some a
  | lib.base.Optional.None


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 Natis a type, whereasOptionalby 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 areNoneandSome),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.Zhas a data constructorC,the generated term and pattern forCwill 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