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 are themselves 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:fun{a:t@ype} list0_length (xs: list0 a): int = ( case+ xs of | list0_cons (_, xs) => 1 + list0_length<a> (xs) | list0_nil () => 0 ) (* end of [list0_length] *)
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:fun divopt ( x: int, y: int ) : option0 (int) = if y != 0 then option0_some{int}(x/y) else option0_none((*void*)) // end of [divopt]
fun{ a:t@ype } list0_last ( xs: list0 a ) : option0 (a) = let // fun loop (x: a, xs: list0 a): a = ( case+ xs of | list0_nil () => x | list0_cons (x, xs) => loop (x, xs) ) (* end of [loop] *) // in case+ xs of | list0_nil () => option0_none((*void*)) | list0_cons (x, xs) => option0_some{a}(loop (x, xs)) end // end of [list0_last]