我在OCaml中有非常简单的签名和模块:
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;;
我不能使用像
这样的结构M2.y
除非我将模块指定为,否则获取3
module M2 : S with type t = int = struct ...
为什么会这样?已有声明type t = int
答案 0 :(得分:3)
int
的具体M2.y
值确实无效,因为满足以下两个条件:
签名y
中S
的类型为抽象
(那里没有type t = ...
)
模块M2
相对于签名S
不透明
(换句话说,它仅限于签名S
通过符号: S
)
结果,你确实获得了:
let test = M2.y ;;
(* val test : M2.t = <abstr> *)
根据关键字<abstr>
的建议,这与抽象类型的概念有关。这个概念是OCaml的输入规则强制执行的一个非常强大的功能,它可以防止具有签名S
的模块的任何用户检查这种抽象类型的具体内容。因此,通过仔细分离ADT的实现和签名,此属性对于在OCaml中实现所谓的abstract data types (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 *)
但在实践中,这并不是很有趣,因为你失去了普遍性。然而,一个更有趣的方法是在签名中添加“评估者”或“漂亮的打印机”功能,例如下面的值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 *)
否则,如果模块M2
变为透明,则获得:
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。
希望这有帮助