モジュールの主目的は、関連する定義(データ型の定義とその型に対する処理)をまとめてパッケージ化し、それらの定義を一貫性のある名前付けの枠組みの元で管理することにあります。これにより名前が不足してしまったり、うっかり間違えてしまいそうな名前が氾濫することを避ける事が出来ます。
そのようなパッケージはストラクチャ(structure)と呼ばれ、任意の定義列を持つ struct
... end
という形で導入します。
ストラクチャは通常 module
束縛によって名前を与えられます。
以下には例として、優先度付きキューの型とそれに対する処理をまとめたストラクチャを示します。
#
module PrioQueue = struct type priority = int type 'a queue = Empty | Node of priority * 'a * 'a queue * 'a queue let empty = Empty let rec insert queue prio elt = match queue with Empty -> Node(prio, elt, Empty, Empty) | Node(p, e, left, right) -> if prio <= p then Node(prio, elt, insert right p e, left) else Node(p, e, insert right prio elt, left) exception Queue_is_empty let rec remove_top = function Empty -> raise Queue_is_empty | Node(prio, elt, left, Empty) -> left | Node(prio, elt, Empty, right) -> right | Node(prio, elt, (Node(lprio, lelt, _, _) as left), (Node(rprio, relt, _, _) as right)) -> if lprio <= rprio then Node(lprio, lelt, remove_top left, right) else Node(rprio, relt, left, remove_top right) let extract = function Empty -> raise Queue_is_empty | Node(prio, elt, _, _) as queue -> (prio, elt, remove_top queue) end;;
module PrioQueue : sig type priority = int type 'a queue = Empty | Node of priority * 'a * 'a queue * 'a queue val empty : 'a queue val insert : 'a queue -> priority -> 'a -> 'a queue exception Queue_is_empty val remove_top : 'a queue -> 'a queue val extract : 'a queue -> priority * 'a * 'a queue end
ストラクチャの外から、その要素を参照するときは「ドット表記」を使います。
ドット表記はストラクチャ名で修飾した識別子です。例えば、文脈から見て値が来るところに PrioQueue.insert
とあれば、ストラクチャ PrioQueue
の中で定義されている関数 insert
を指定したことになります。同様に、文脈から見て型が来るところに PrioQueue.queue
とあれば、 PrioQueue
の中で定義されている型 queue
を指定したことになります。
#
PrioQueue.insert PrioQueue.empty 1 "hello";;
- : string PrioQueue.queue = PrioQueue.Node (1, "hello", PrioQueue.Empty, PrioQueue.Empty)