我们可以将模块打包为 value 并将其解包回模块(模块作为一等公民)。此外,我们可以将模块类型打包到类型,但是......是否可以从类型中解压缩模块类型?如果是 - 如何?如果不是 - 为什么?下面的草图显示了我的意思。
module type S = sig
type t
end
type 'a t = (module S with type t = 'a)
module type S' = sig
include SIG_FROM ( int t )
end
或者
module type S'' = SIG_FROM ( int t )
补充说明:
那么我为什么要问这个问题。很多时候 Ocaml 无法推断出第一类模块实例的类型,因此应该对其进行注释。可以通过两种方式进行:
1) 通过签名
module type INTERNAL_S =
EXTERNAL_S with type a = char
and type b = int
and type c = string
let f (module M : INTERNAL_S) a b c =
M.f a b (c * 2)
2) 按类型
type e =
( module EXTERNAL_S
with type a = char
and type b = int
and type c = string
)
let f ((module M) : e) a b =
M.f a (b * 2)
常见的第二种方式更短且易于阅读,尤其是在签名 (.mli) 中。
val g : (module INTERNAL_S) -> (module INTERNAL_S) ->
char -> int -> string
val g : e -> e -> char -> int -> string
我们从模块类型创建类型以简化代码阅读或在必要的情况下(例如当函子期望它时)。有时我只需要类型,但也必须声明模块类型,因为从模块类型约束新类型的支持是有限的
并且缺少从类型(绑定到模块类型)中约束新类型(绑定到模块类型)。
(* this kind of constructing is possible *)
let x : 'a t = (module struct
include A
include B
include (val C.some_value)
let new_f o = o
end)
(* but this isn't *)
type 'a t = (module sig
include A with type t = t
include B with type t := t
include SIG_FROM ( (int, int) sig_type )
val new_f : t -> t
end)
至于我,这种方式让模块更加一流。此外,它与实例和模块之间的关系是对称的(据我了解let x = (module X)
,let module X = (val x)
也是绑定)。对称性——很好(例如它部分存在于函数和函子之间)。但正如我在这个地方看到的那样,OCaml 在模块语言和核心语言之间存在边界。我问“how”是因为有希望,问“why”是因为确定这个问题是在OCaml的设计过程中打开的,所以这个边界是基于一些决定和原因。