#module Fifo = structtype 'a queue = { front: 'a list; rear: 'a list } let make front rear = match front with | [] -> { front = List.rev rear; rear = [] } | _ -> { front; rear } let empty = { front = []; rear = [] } let is_empty = function { front = []; _ } -> true | _ -> falselet add x q = make q.front (x :: q.rear) exception Empty let top = function | { front = []; _ } -> raise Empty | { front = x :: _; _ } -> x let pop = function | { front = []; _ } -> raise Empty | { front = _ :: f; rear = r } -> make f r end;;
module Fifo : sigtype 'a queue = { front : 'a list; rear : 'a list; } val make : 'a list -> 'a list -> 'a queue val empty : 'a queue val is_empty : 'a queue -> bool val add : 'a -> 'a queue -> 'a queue exception Empty val top : 'a queue -> 'a val pop : 'a queue -> 'a queue end
#let at_most_one_element x = match x with | Fifo.{ front = ([] | [_]); rear = [] } -> true | _ -> false ;;
val at_most_one_element : 'a Fifo.queue -> bool = <fun>
也可以使用 include 語句將模組的元件複製到另一個模組中。這對於擴充現有模組特別有用。舉例來說,我們可以新增一些函數,這些函數在佇列為空時返回可選值,而不是拋出例外。
#module FifoOpt = structinclude Fifo let top_opt q = if is_empty q then None else Some(top q) let pop_opt q = if is_empty q then None else Some(pop q) end;;
module FifoOpt : sigtype 'a queue = 'a Fifo.queue = { front : 'a list; rear : 'a list; } val make : 'a list -> 'a list -> 'a queue val empty : 'a queue val is_empty : 'a queue -> bool val add : 'a -> 'a queue -> 'a queue exception Empty val top : 'a queue -> 'a val pop : 'a queue -> 'a queue val top_opt : 'a queue -> 'a option val pop_opt : 'a queue -> 'a queue option end
#moduletype FIFO = sigtype 'a queue (* 現在是抽象型別 *)val empty : 'a queue val add : 'a -> 'a queue -> 'a queue val top : 'a queue -> 'a val pop : 'a queue -> 'a queue exception Empty end;;
moduletype FIFO = sigtype 'a queue val empty : 'a queue val add : 'a -> 'a queue -> 'a queue val top : 'a queue -> 'a val pop : 'a queue -> 'a queue exception Empty end
將 Fifo 結構限制為此簽章會產生 Fifo 結構的另一個視圖,其中 make 函數不可存取,並且佇列的實際表示被隱藏
#moduletype FIFO_WITH_OPT = siginclude FIFO val top_opt: 'a queue -> 'a option val pop_opt: 'a queue -> 'a queue option end;;
moduletype FIFO_WITH_OPT = sigtype 'a queue val empty : 'a queue val add : 'a -> 'a queue -> 'a queue val top : 'a queue -> 'a val pop : 'a queue -> 'a queue exception Empty val top_opt : 'a queue -> 'a option val pop_opt : 'a queue -> 'a queue option end
函子是從模組到模組的「函式」。函子可讓您建立參數化模組,然後提供其他模組作為參數,以取得特定的實作。例如,將集合實作為排序清單的 Set 模組可以參數化,以便與提供元素類型和比較函式 compare 的任何模組搭配使用(例如 OrderedString)
#type comparison = Less | Equal | Greater;;
type comparison = Less | Equal | Greater
#moduletype ORDERED_TYPE = sigtype t val compare: t -> t -> comparison end;;
moduletype ORDERED_TYPE = sigtype t val compare : t -> t -> comparison end
#module Set = functor (Elt: ORDERED_TYPE) -> structtype element = Elt.t type set = element list let empty = [] letrec add x s = match s with [] -> [x] | hd::tl -> match Elt.compare x hd with Equal -> s (* x 已經在 s 中 *) | Less -> x :: s (* x 小於 s 的所有元素 *) | Greater -> hd :: add x tl letrec member x s = match s with [] -> false | hd::tl -> match Elt.compare x hd with Equal -> true(* x 屬於 s *) | Less -> false(* x 小於 s 的所有元素 *) | Greater -> member x tl end;;
module Set : functor (Elt : ORDERED_TYPE) -> sigtype element = Elt.t type set = element list val empty : 'a list val add : Elt.t -> Elt.t list -> Elt.t list val member : Elt.t -> Elt.t list -> bool end
透過將 Set 函子套用到實作已排序類型的結構,我們取得此類型的集合運算
#module OrderedString = structtype t = string let compare x y = if x = y then Equal elseif x < y then Less else Greater end;;
module OrderedString : sigtype t = string val compare : 'a -> 'a -> comparison end
#module StringSet = Set(OrderedString);;
module StringSet : sigtype element = OrderedString.t type set = element list val empty : 'a list val add : OrderedString.t -> OrderedString.t list -> OrderedString.t list val member : OrderedString.t -> OrderedString.t list -> bool end
如同 Fifo 範例中所示,隱藏 set 類型的實際實作會是一種良好的風格,如此一來,結構的使用者將不會依賴集合為清單,而且我們稍後可以切換到另一個更有效率的集合表示法,而不會破壞他們的程式碼。這可以透過使用適當的函子簽章限制 Set 來達成
#moduletype SETFUNCTOR = functor (Elt: ORDERED_TYPE) -> sigtype element = Elt.t (* 具體 *)type set (* 抽象 *)val empty : set val add : element -> set -> set val member : element -> set -> bool end;;
moduletype SETFUNCTOR = functor (Elt : ORDERED_TYPE) -> sigtype element = Elt.t type set val empty : set val add : element -> set -> set val member : element -> set -> bool end
module AbstractStringSet : sigtype element = OrderedString.t type set = AbstractSet(OrderedString).set val empty : set val add : element -> set -> set val member : element -> set -> bool end
module WrongStringSet : sigtype element = WrongSet(OrderedString).element type set = WrongSet(OrderedString).set val empty : set val add : element -> set -> set val member : element -> set -> bool end
這裡的問題在於 SET 抽象地指定了類型 element,因此函子結果中的 element 類型與其參數中的 t 類型之間的相等性被遺忘了。因此,WrongStringSet.element 與 string 不是相同的類型,並且 WrongStringSet 的操作不能應用於字串。如上所示,重要的是簽章 SET 中的類型 element 必須宣告為等於 Elt.t;不幸的是,由於 SET 是在 Elt 不存在的上下文中定義的,因此這在上述情況下是不可能的。為了克服這個困難,OCaml 提供了 with type 結構在簽章上,允許用額外的類型相等性來豐富簽章。
module AbstractSet2 : functor (Elt : ORDERED_TYPE) -> sigtype element = Elt.t type set val empty : set val add : element -> set -> set val member : element -> set -> bool end
與簡單結構的情況一樣,也提供了另一種語法來定義函子並限制它們的結果
module AbstractSet2(Elt: ORDERED_TYPE) : (SET with type element = Elt.t) =
struct ... end;;
module NoCaseStringSet : sigtype element = NoCaseString.t type set = AbstractSet(NoCaseString).set val empty : set val add : element -> set -> set val member : element -> set -> bool end
Error: This expression has type AbstractStringSet.set = AbstractSet(OrderedString).set but an expression was expected of type NoCaseStringSet.set = AbstractSet(NoCaseString).set
module Aux: sig (* contents of Aux.mli *) end
= struct (* contents of Aux.ml *) end;;
module Main: sig (* contents of Main.mli *) end
= struct (* contents of Main.ml *) end;;