混凝土,
int
的值
M2.y
确实不可用,因为满足以下两个条件:
-
的类型
y
是
摘要
在签名中
S
(没有
type t = ...
此处)
-
模块
M2
是制造的
不透明的
关于签名
S
(换句话说,仅限于签名
S
通过
符号
: S
)
因此,您确实获得:
let test = M2.y ;;
(* val test : M2.t = <abstr> *)
根据关键字建议
<abstr>
,这与
抽象类型
. 这个概念是由OCaml的类型规则强制实现的一个非常强大的特性,它可以防止模块的任何用户拥有签名
S
检查这种抽象类型的具体内容。因此,此属性对于实现所谓的
abstract data types (ADT)
在OCaml中,通过仔细分离ADT的实现和签名。
如果缺少上述两个条件中的任何一个,则类型将不再是抽象的,并且
y
将出现。
更准确地说:
-
如果类型
t
混凝土制成,您可以获得:
module type S = sig
type t = int
val y : t
end
module M2 : S = struct
type t = int
let x = 1
let y = x+2
end
let test = M2.y ;;
(* val test : M2.t = 3 *)
但在实践中,这不是很有趣,因为你失去了一般性。然而,更有趣的方法是在签名中添加“evaluator”或“pretty printer”函数,例如值
int_of_t
以下内容:
module type S = sig
type t
val y : t
val int_of_t : t -> int
end
module M2 : S = struct
type t = int
let x = 1
let y = x+2
let int_of_t x = x
end
let test = M2.(int_of_t y) ;;
(* val test : int = 3 *)
-
否则,如果模块
平方米
是透明的,您可以获得:
module type S = sig
type t
val y : t
end
module M2 (* :S *) = struct
type t = int
let x = 1
let y = x+2
end
let test = M2.y ;;
(* val test : int = 3 *)
最后,值得注意的是,除了抽象类型的特性之外,OCaml还提供了
私有类型
这可以看作是模块化开发中使用的具体类型和抽象类型之间的权衡。有关此概念的更多详细信息,请参见示例
Chap. 8 of Caml ref man
.