第 12 章 語言擴展

4 局部抽象類型

(OCaml 3.12 引入,4.03 版本加入簡短語法)

參數::= ...
 (type { 類型構造名稱 }+)

表達式 fun ( type 類型構造名稱 ) -> 表達式 引入了一個名為 類型構造名稱 的類型構造子,它在子表達式的範圍內被視為抽象的,然後被替換為一個新的類型變數。請注意,與語法可能暗示的相反,表達式 fun ( type 類型構造名稱 ) -> 表達式 本身並不會像常規抽象那樣暫停 表達式 的求值。之所以選擇這種語法,是為了使其在函數聲明的上下文中能很好地適應,因為通常在這種情況下使用。可以自由地將常規函數參數與偽類型參數混合使用,例如:

let f = fun (type t) (foo : t list) -> …

甚至可以使用替代語法來聲明函數

let f (type t) (foo : t list) = …

如果需要引入多個局部抽象類型,可以使用語法 fun ( type 類型構造名稱1類型構造名稱n ) -> 表達式 作為 fun ( type 類型構造名稱1 ) ->-> fun ( type 類型構造名稱n ) -> 表達式 的語法糖。例如,

let f = fun (type t u v) -> fun (foo : (t * u * v) list) -> … let f' (type t u v) (foo : (t * u * v) list) = …

這種結構很有用,因為它引入的類型構造子可以用在不允許使用類型變數的地方。例如,可以在多型函數內的局部模組中定義一個例外。

let f (type t) () = let module M = struct exception E of t end in (fun x -> M.E x), (function M.E x -> Some x | _ -> None)

這是另一個例子

let sort_uniq (type s) (cmp : s -> s -> int) = let module S = Set.Make(struct type t = s let compare = cmp end) in fun l -> S.elements (List.fold_right S.add l S.empty)

它對於一級模組(請參閱第12.5節)和廣義代數資料類型(GADTs:請參閱第12.10節)也非常有用。

多型語法

(在 OCaml 4.00 中引入)

let 綁定::= ...
 值名稱:type { 類型構造名稱 }+.類型表達式=表達式
 
類別欄位::= ...
 method [private] 方法名稱:type { 類型構造名稱 }+.類型表達式=表達式
 method! [private] 方法名稱:type { 類型構造名稱 }+.類型表達式=表達式

(type 類型構造名稱) 語法結構本身不會使它引入的類型變數成為多型,但它可以與需要時的明確多型註釋組合使用。上面的規則是作為語法糖提供的,以便更容易實現這一點

let rec f : type t1 t2. t1 * t2 list -> t1 = …

會自動擴展為

let rec f : 't1 't2. 't1 * 't2 list -> 't1 = fun (type t1) (type t2) -> ( … : t1 * t2 list -> t1)

當定義涉及 GADTs 的遞迴函數時,此語法非常有用,請參閱第12.10節以獲得更詳細的解釋。

方法定義也提供了相同的功能。