These encompass both enumeration and record types in other languages. A derived type is defined using ‘:- type type ---> body’. (Note there are three dashes in that arrow. It should not be confused with the two-dash arrow used for DCGs or the one-dash arrow used for if-then-else.) If the type term is a functor of arity zero (i.e. one having zero arguments), it names a monomorphic type. Otherwise, it names a polymorphic type; the arguments of the functor must be distinct type variables. The body term is defined as a sequence of constructor definitions separated by semi-colons.
Ordinarily, each constructor definition must be a functor whose arguments (if any) are types. Ordinary discriminated union definitions must be transparent: all type variables occurring in the body must also occur in the type.
However, constructor definitions can optionally be existentially typed. In that case, the functor will be preceded by an existential type quantifier and can optionally be followed by an existential type class constraint. For details, see Existential types. Existentially typed discriminated union definitions need not be transparent.
The arguments of constructor definitions may be labelled.
These labels cause the compiler to generate functions which can
be used to conveniently select and update fields of a term
in a manner independent of the definition of the type
(see Field access functions). A labelled argument has the
form fieldname :: Type. It is an error for
two fields in the same module to have the same label.
Here are some examples of discriminated union definitions:
:- type fruit
---> apple
; orange
; banana
; pear.
:- type strange
---> foo(int)
; bar(string).
:- type employee
---> employee(
name :: string,
age :: int,
department :: string
).
:- type tree
---> empty
; leaf(int)
; branch(tree, tree).
:- type list(T)
---> []
; [T | list(T)].
:- type pair(T1, T2)
---> T1 - T2.
If the body of a discriminated union type definition
contains a term whose top-level functor is ';'/2,
the semi-colon is normally assumed to be a separator.
This makes it difficult to define a type
whose constructors include ';'/2.
To allow this, curly braces can be used to quote the semi-colon.
It is then also necessary to quote curly braces.
The following example illustrates this:
:- type tricky
---> { int ; int }
; { { int } }.
This defines a type with two constructors, ';'/2 and '{}'/1,
whose argument types are all int. We recommend against using
constructors named '{}' because of the possibility of confusion
with the builtin tuple types.
Each discriminated union type definition introduces a distinct type. Mercury considers two discriminated union types that have the same bodies to be distinct types (name equivalence). Having two different definitions of a type with the same name and arity in the same module is an error.
Constructors may be overloaded among different types: there may be any number of constructors with a given name and arity, so long as they all have different types. However, there must not be more than one constructor with the same name, arity, and result type in the same module. (There is no particularly good reason for this restriction; in the future we may allow several such functors as long as they have different argument types.) Note that excessive overloading of constructors can slow down type checking and can make the program confusing for human readers, so overloading should not be over-used.