第 12 章 語言擴展

14 可擴展變體型別

(在 OCaml 4.02 中引入)

type-representation::= ...
 =..
 
specification::= ...
 type [type-params] typeconstrtype-extension-spec
 
definition::= ...
 type [type-params] typeconstrtype-extension-def
 
type-extension-spec::=+= [private] [|] constr-decl { |constr-decl }
 
type-extension-def::=+= [private] [|] constr-def { |constr-def }
 
constr-def::= constr-decl
 constr-name=constr
 

可擴展變體型別是可以使用新的變體建構子擴展的變體型別。可擴展變體型別使用 .. 定義。新的變體建構子使用 += 添加。

module Expr = struct type attr = .. type attr += Str of string type attr += | Int of int | Float of float end

在可擴展變體型別上進行模式比對需要一個預設案例來處理未知的變體建構子

let to_string = function | Expr.Str s -> s | Expr.Int i -> Int.to_string i | Expr.Float f -> string_of_float f | _ -> "?"

一個現有的可擴展變體型別例子是用於例外處理的內建 exn 型別。實際上,可以使用型別擴展語法宣告例外建構子

type exn += Exc of int

可擴展變體建構子可以重新綁定到不同的名稱。這允許從另一個模組匯出變體。

# let not_in_scope = Str "Foo";;
Error: 未綁定的建構子 Str
type Expr.attr += Str = Expr.Str
# let now_works = Str "foo";;
val now_works : Expr.attr = Expr.Str "foo"

可擴展變體建構子可以宣告為 private。與正規變體一樣,這可以防止它們透過建構子應用直接建構,同時仍然允許它們在模式比對中進行解構。

module B : sig type Expr.attr += private Bool of int val bool : bool -> Expr.attr end = struct type Expr.attr += Bool of int let bool p = if p then Bool 1 else Bool 0 end
# let inspection_works = function | B.Bool p -> (p = 1) | _ -> true;;
val inspection_works : Expr.attr -> bool = <fun>
# let construction_is_forbidden = B.Bool 1;;
Error: 無法使用私有建構子 Bool 來建立 Expr.attr 型別的值

14.1 私有可擴展變體型別

(在 OCaml 4.06 中引入)

type-representation::= ...
 =private..
 

可擴展變體型別可以宣告為 private。這可以防止直接宣告新的建構子,但允許在介面中引用擴展建構子。

module Msg : sig type t = private .. module MkConstr (X : sig type t end) : sig type t += C of X.t end end = struct type t = .. module MkConstr (X : sig type t end) = struct type t += C of X.t end end