第 11 章 OCaml 語言

11 模組表達式(模組實作)

模組表達式是模組層級中與值表達式等效的概念:它們評估為模組,從而為模組類型中表達的規格提供實作。

module-expr::= module-path
 struct [ module-items ] end
 functor(module-name:module-type)->module-expr
 module-expr(module-expr)
 (module-expr)
 (module-expr:module-type)
 
module-items::={ ;; } ( definition ∣ expr ) { { ;; } ( definition ∣ ;;expr) } { ;; }
 
definition::= let [rec] let-binding { andlet-binding }
 externalvalue-name:typexpr=external-declaration
 type-definition
 exception-definition
 class-definition
 classtype-definition
 modulemodule-name { (module-name:module-type) } [ :module-type ]  =module-expr
 moduletypemodtype-name=module-type
 openmodule-path
 includemodule-expr

另請參閱以下語言擴展:遞迴模組一級模組open 陳述式中的覆寫屬性擴展節點生成函子

11.1 簡單模組表達式

表達式 module-path 評估為綁定到名稱 module-path 的模組。

表達式 ( module-expr ) 評估為與 module-expr 相同的模組。

表達式 ( module-expr : module-type ) 檢查 module-expr 的類型是否為 module-type 的子類型,也就是說,在 module-type 中指定的所有元件都在 module-expr 中實作,並且其實作符合 module-type 中給出的要求。換句話說,它會檢查實作 module-expr 是否符合類型規格 module-type。整個表達式評估為與 module-expr 相同的模組,但未在 module-type 中指定的所有元件都會被隱藏,且無法再存取。

11.2 結構

結構 structend 是值名稱、類型名稱、例外、模組名稱和模組類型名稱的定義集合。定義會依其在結構中出現的順序評估。定義執行的綁定範圍會延伸至結構的結尾。因此,定義可能會參考相同結構中較早定義所綁定的名稱。

為了與頂層短語相容(第‍14 章),結構中每個定義的前後都允許使用選用的 ;;。這些 ;; 沒有語意上的意義。同樣地,結構的元件中也允許使用前面加上 ;;expr。它等同於 let _ = expr,也就是說,會評估 expr 的副作用,但不將其繫結到任何識別碼。如果 expr 是結構的第一個元件,則可以省略前面的 ;;

值定義

值定義 let [rec] let-binding { and let-binding } 以與 letin … 表達式相同的方式繫結值名稱(請參閱第‍11.7.2 節)。繫結左側出現的值名稱會繫結到右側對應的值。

值定義 external value-name : typexpr = external-declarationvalue-name 實作為 external-declaration 中指定的外部函式(請參閱第‍22 章)。

類型定義

一個或多個類型元件的定義會寫為 type typedef { and typedef },並且包含類型名稱的相互遞迴定義序列。

例外定義

例外是使用語法 exception constr-declexception constr-name = constr 來定義。

類別定義

一個或多個類別的定義會寫為 class class-binding { and class-binding },並且包含類別名稱的相互遞迴定義序列。類別定義在第‍11.9.3 節中更精確地說明。

類別類型定義

一個或多個類別的定義會寫為 class type classtype-def { and classtype-def },並且包含類別類型名稱的相互遞迴定義序列。類別類型定義在第‍11.9.5 節中更精確地說明。

模組定義

用於定義模組元件的基本形式是 module module-name = module-expr,這會評估 module-expr,並將結果繫結到名稱 module-name

可以寫成

而不是

另一個衍生的形式是

module 模組名稱 ( 名稱1 : 模組類型1 )( 名稱n : 模組類型n ) = 模組表達式

這等同於

module 模組名稱 = functor ( 名稱1 : 模組類型1 ) ->-> 模組表達式

模組類型定義

模組類型的定義寫作 module type 模組類型名稱 = 模組類型。它將名稱 模組類型名稱 綁定到由表達式 模組類型 所表示的模組類型。

開啟模組路徑

結構中的表達式 open 模組路徑 並不定義任何元件或執行任何綁定。它僅影響結構中後續項目的解析,允許以它們的簡單名稱 名稱 來引用由 模組路徑 所表示的模組的元件,而不是通過路徑存取 模組路徑 . 名稱open 的作用域在結構表達式的結尾處停止。

包含另一個結構的元件

結構中的表達式 include 模組表達式 會在目前的結構中重新匯出由 模組表達式 所表示的結構的所有定義。例如,如果你定義一個模組 S 如下

module S = struct type t = int let x = 2 end

將模組 B 定義為

module B = struct include S let y = (x + 1 : t) end

等同於將其定義為

module B = struct type t = S.t let x = S.x let y = (x + 1 : t) end

openinclude 之間的區別在於,open 只是為開啟的結構的元件提供短名稱,而沒有定義目前結構的任何元件,而 include 也會為包含的結構的元件添加定義。

11.3 函子

函子定義

表達式 functor ( 模組名稱 : 模組類型 ) -> 模組表達式 會求值為一個函子,該函子接受類型為 模組類型1 的模組作為引數,將 模組名稱 綁定到這些模組,在擴展的環境中評估 模組表達式,並將結果模組作為結果返回。對函子引數的類型沒有限制;特別是,函子可以將另一個函子作為引數(「高階」函子)。

當結果模組表達式本身是一個函子時,

functor ( 名稱1 : 模組類型1 ) ->-> functor ( 名稱n : 模組類型n ) -> 模組表達式

可以使用縮寫形式

functor ( 名稱1 : 模組類型1 )( 名稱n : 模組類型n ) -> 模組表達式

函子應用

表達式 模組表達式1 ( 模組表達式2 ) 會將 模組表達式1 評估為函子,將 模組表達式2 評估為模組,並將前者應用於後者。 模組表達式2 的類型必須與函子 模組表達式1 的引數預期的類型匹配。