We use type definitions to define data structures that cannot fit easily into basic data types that are predefined in Caml. A type definition always introduces a new type that is incompatible with any other type.
Type definitions are introduced by the keyword
type
. Type definitions are recursive and can be
polymorphic (in this case the new type possesses some type arguments
(see,
or)
). To simultaneously define more than one type, just sequence
definitions with the keyword
and
.
Table of contents:
There are three kinds of data types that you can define in Caml:
An enumerated type is a sum type with only constants. For instance, a type with 3 constants:
#type colour = Blue | White | Red;; Type colour defined. #Blue;; - : colour = Blue
The names Blue
White
and Red
are the constructors of the colour
type. These
constructors may have arguments.
Consider polynomes, that can be sparse (many zeros) or dense (only a
few zeros):
#type polynom = Sparse of int list | Dense of int vect;; Type polynom defined. #let nul = Sparse [0];; nul : polynom = Sparse [0] #let un_plus_two_x = Dense [|1; 2|];; un_plus_two_x : polynom = Dense [|1; 2|]
Constructors serve case selection via pattern matching:
#let minus_pol = function | Sparse l -> Sparse (map (function x -> - x) l) | Dense v -> Dense (map_vect (function x -> - x) v);; minus_pol : polynom -> polynom = <fun> #minus_pol nul;; - : polynom = Sparse [0] #minus_pol un_plus_two_x;; - : polynom = Dense [|-1; -2|]
Note: usage is to begin a constructor by a upper case letter.
For an example of polymorphic sum type see.
A record is a list of fields, each field being a label with its associated value:
#type person = {Name : string; Age : int};; Type person defined. #let x = {Name = "Joe"; Age = 7};; x : person = {Name="Joe"; Age=7} #x.Name;; - : string = "Joe"
Fields in a record type may be declared ``mutable'', when the type is
defined.
It is then possible to modify the content of the ``mutable'' field,
using the syntactic construct
r.label <- new_value
.
For instance, the balance of a bank account can be updated, but the account number is a constant:
#type account = {Number : int; mutable Balance : float};; Type account defined. #let account_ref = ref 0;; account_ref : int ref = ref 0 #let make_account initial_credit = incr account_ref; {Number = !account_ref; Balance = initial_credit};; make_account : float -> account = <fun> #let joes_account = make_account 500.0;; joes_account : account = {Number=1; Balance=500.0} #let credit sum account = account.Balance <- account.Balance +. sum;; credit : float -> account -> unit = <fun> #credit 100.0 joes_account;; - : unit = () #joes_account;; - : account = {Number=1; Balance=600.0}
As for every kind of type in Caml, polymorphic record types are defined by adding the list of type arguments of the new type.
For instance, we define the type of polymorphic and mutable cells (or binary trees):
#type ('a, 'b) cell = {mutable Car : 'a; mutable Cdr : 'b};; Type cell defined. #{Car = 1; Cdr = "ok"};; - : (int, string) cell = {Car=1; Cdr="ok"} #let rplaca cell val = cell.Car <- val;; rplaca : ('a, 'b) cell -> 'a -> unit = <fun>
Polymorphic sum types are also definable:
#type ('a, 'b) sexpr = Symbol of string | Cell of ('a, 'b) cell;; #let nil = Symbol "";; nil : ('a, 'b) sexpr = Symbol "" #let cons v1 v2 = Cell {Car = v1; Cdr = v2};; cons : 'a -> 'b -> ('a, 'b) sexpr = <fun> #let l = cons 1 (cons 2 nil);; l : (int, (int, ('_a, '_b) sexpr) sexpr) sexpr = Cell {Car=1; Cdr=Cell {Car=2; Cdr=Symbol ""}}
Type abbreviation define aliases for type expressions:
#type counter == int;; Type counter defined. #let x = (1 : counter);; x : counter = 1
Values of an abbreviation type may be considered as values of the corresponding type expression:
#x + 1;; - : int = 2
Type abbreviations are used in modules (to define a type needed to meet the module specifications) or for documentation purposes.
Contact the author Pierre.Weis@inria.fr