第 11 章 OCaml 語言

10 模組類型(模組規格)

模組類型是模組層級的類型表達式等效物:它們指定模組的通用形狀和類型屬性。

module-type::= modtype-path
 sig { specification [;;] } end
 functor(module-name:module-type)->module-type
 module-type->module-type
 module-typewithmod-constraint { andmod-constraint }
 (module-type)
 
mod-constraint::= type [type-params] typeconstrtype-equation { type-constraint }
 modulemodule-path=extended-module-path
 
specification::= valvalue-name:typexpr
 externalvalue-name:typexpr=external-declaration
 type-definition
 exceptionconstr-decl
 class-specification
 classtype-definition
 modulemodule-name:module-type
 modulemodule-name { (module-name:module-type) } :module-type
 moduletypemodtype-name
 moduletypemodtype-name=module-type
 openmodule-path
 includemodule-type

另請參閱以下語言擴展:恢復模組的類型在簽章內進行替換類型級模組別名屬性擴展節點生成式函子模組類型替換

10.1 簡單模組類型

表達式 modtype-path 等同於綁定到名稱 modtype-path 的模組類型。表達式 ( module-type ) 表示與 module-type 相同的類型。

10.2 簽章

簽章是結構的類型規格。簽章 sigend 是值名稱、類型名稱、異常、模組名稱和模組類型名稱的類型規格集合。如果結構為簽章中指定的所有名稱提供定義(實作)(以及可能更多),並且這些定義符合簽章中給定的類型要求,則該結構將匹配簽章。

簽章中的每個規格之後允許使用一個可選的 ;;。它用作語法分隔符,沒有語義含義。

值規格

簽章中值元件的規格寫為 val value-name : typexpr,其中 value-name 是值的名稱,而 typexpr 是其預期的類型。

形式 external value-name : typexpr = external-declaration 類似,但它還要求該名稱實作為 external-declaration 中指定的外部函數(請參閱第 22 章)。

類型規格

簽章中一個或多個類型元件的規格寫為 type typedef { and typedef },它由類型名稱的相互遞歸定義序列組成。

簽章中的每個類型定義都指定一個可選的類型方程式 = typexpr 和一個可選的類型表示 = constr-decl … 或 = { field-decl}。匹配結構中類型名稱的實作必須與方程式中指定的類型表達式(如果給定)相容,並具有指定的表示形式(如果給定)。相反,該簽章的使用者將能夠依賴類型方程式或類型表示形式(如果給定)。更準確地說,我們有以下四種情況

抽象類型:沒有方程式,沒有表示形式。
 ‍
在簽章中定義為抽象類型的名稱可以在匹配的結構中透過任何類型的類型定義來實作(前提是它具有相同數量的類型參數)。類型的確切實作將對結構的使用者隱藏。特別是,如果該類型實作為變體類型或記錄類型,則關聯的建構函式和欄位將無法讓使用者存取;如果該類型實作為縮寫,則類型名稱與縮寫右側之間的類型相等性將對結構的使用者隱藏。結構的使用者認為該類型與任何其他類型不相容:已產生新的類型。
類型縮寫:一個方程式 = typexpr,沒有表示形式。
 ‍
類型名稱必須透過與 typexpr 相容的類型實作。結構的所有使用者都知道類型名稱與 typexpr 相容。
新的變體類型或記錄類型:沒有方程式,有一個表示形式。
 ‍
類型名稱必須透過具有指定確切建構函式或欄位的變體類型或記錄類型實作。結構的所有使用者都可以存取建構函式或欄位,並且可以使用它們來建立或檢查該類型的值。但是,結構的使用者認為該類型與任何其他類型不相容:已產生新的類型。
重新匯出的變體類型或記錄類型:一個方程式,一個表示形式。
 ‍
這種情況結合了前兩種情況:該類型的表示形式對所有使用者可見,並且不會產生新的類型。

異常規格

簽章中的規格 exception constr-decl 要求匹配的結構提供具有定義中指定的名稱和參數的異常,並使該異常可供結構的所有使用者使用。

類別規格

簽章中一個或多個類別的規格寫為 class class-spec { and class-spec },它由類別名稱的相互遞歸定義序列組成。

類別規格在第 11.9.4 節中進行了更精確的描述。

類別類型規格

簽章中一個或多個類別類型的規格寫為 class type classtype-def { and classtype-def },它由類別類型名稱的相互遞歸定義序列組成。類別類型規格在第 11.9.5 節中進行了更精確的描述。

模組規格

在簽章中,模組組件的規格寫成 module 模組名稱 : 模組類型,其中 模組名稱 是模組組件的名稱,而 模組類型 是其預期的類型。模組可以任意巢狀結構;特別是,函子可以作為結構的組件,而函子類型可以作為簽章的組件。

要指定一個作為函子的模組組件,可以寫成

module 模組名稱 ( 名稱1 : 模組類型1 )( 名稱n : 模組類型n ) : 模組類型

而不是

module 模組名稱 : functor ( 名稱1 : 模組類型1 ) ->-> 模組類型

模組類型規格

簽章的模組類型組件可以指定為具體模組類型或抽象模組類型。

抽象模組類型規格 module type 模組類型名稱 允許名稱 模組類型名稱 由符合簽章的任何模組類型實作,但會對簽章的所有使用者隱藏模組類型的實作。

具體模組類型規格 module type 模組類型名稱 = 模組類型 要求名稱 模組類型名稱 由符合簽章的模組類型 模組類型 實作,但會使 模組類型名稱模組類型 之間的相等性對簽章的所有使用者顯而易見。

開啟模組路徑

簽章中的表達式 open 模組路徑 不會指定任何組件。它只會影響簽章後續項目的解析,允許以簡單名稱 名稱 而不是路徑存取 模組路徑 . 名稱 來引用由 模組路徑 表示的模組的組件。open 的作用域會在簽章表達式結束時停止。

包含簽章

簽章中的表達式 include 模組類型 會執行由 模組類型 表示的簽章組件的文字包含。它的行為就像包含簽章的組件被複製到 include 的位置。模組類型 引數必須參照到簽章的模組類型,而不是函子類型。

10.3 函子類型

模組類型表達式 functor ( 模組名稱 : 模組類型1 ) -> 模組類型2 是函子(從模組到模組的函數)的類型,它接受類型為 模組類型1 的模組作為引數,並返回類型為 模組類型2 的模組作為結果。模組類型 模組類型2 可以使用名稱 模組名稱 來參照函子實際引數的類型組件。如果類型 模組類型2 不依賴於 模組名稱 的類型組件,則可以使用替代的簡短語法 模組類型1 -> 模組類型2 來簡化模組類型表達式。函子引數的類型沒有限制;特別是,函子可以接受另一個函子作為引數(「高階」函子)。

當結果模組類型本身是函子時,

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

可以使用縮寫形式

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

10.4 with 運算子

假設 模組類型 表示簽章,則表達式 模組類型 with 模組約束 { and 模組約束 } 表示相同的簽章,其中已將類型方程式添加到某些類型規格中,如 with 關鍵字後的約束所描述。約束 type [類型參數] 類型建構子 = 類型表達式 會將類型方程式 = 類型表達式 新增到受約束簽章的名稱為 類型建構子 的類型組件的規格。約束 module 模組路徑 = 擴充模組路徑 會將類型方程式新增到由 模組路徑 表示的子結構的所有類型組件,使它們等同於由 擴充模組路徑 表示的結構的相應類型組件。

例如,如果模組類型名稱 S 綁定到簽章

        sig type t module M: (sig type u end) end

S with type t=int 表示簽章

        sig type t=int module M: (sig type u end) end

S with module M = N 表示簽章

        sig type t module M: (sig type u=N.u end) end

一個接受兩個類型為 S 的引數的函子,它們共享 t 組件,寫成

        functor (A: S) (B: S with type t = A.t) ...

約束會從左到右添加。在每個約束應用之後,產生的簽章必須是應用約束之前的簽章的子類型。因此,with 運算子只能在簽章的類型組件上添加資訊,但永遠不能刪除資訊。