Code sharing also applies to datatype declarations. For instance,
a commonly used polymorphic datatype list0 is declared as follows:
More precisely,
list0 is a type constructor. Given a type T,
we can form a type
list0(T) for lists consisting of elements
of the type T. For instance,
list0(char) is for character
lists,
list0(int) for integer lists,
list0(list0(int)) for lists whose elements themselves are
integer lists, etc. To a great extent, the need for function templates or
polymorphic functions largely stems from the availability of polymorphic
datatypes. As an example, a function template
list0_length is
implemented as follows for computing the length of any given list:
When applying
list0_length to a list xs, we can in general
write
list0_length(xs), expecting the typechecker to
synthesize a proper type parameter for
list0_length. We may
also write
list0_length<T
>(xs) if the
elements of xs are of the type T. The latter style, though a bit more
verbose, is likely to yield more informative messages in case type-errors
occur.
Another commonly used polymorphic datatype option0 is
declared as follows:
A typical use of
option0 is to perform some kind of
error-handling. Suppose that we are to implement a function doing integer
division and we want to make sure that the function returns even if it is
called in a case where the divisor equals 0. This can be done as follows:
By inspecting what
divopt returns, we can tell whether integer
division has been done normally or an error of divsion-by-zero has
occurred. A realistic use of
option0 is shown in the following
implementation of
list0_last:
When applied to a list,
list0_last returns an optional
value. If the value matches the pattern
option0_none(), then
the list is empty. Otherwise, the value is formed by applying
option0_some to the last element in the list.