fil*_*ard 2 ocaml module signature
我在 OCaml 中有非常简单的签名和模块:
module type S = sig
type t
val y : t
end;;
Run Code Online (Sandbox Code Playgroud)
和
module M2 : S = struct
type t = int
let x = 1
let y = x+2
end;;
Run Code Online (Sandbox Code Playgroud)
我不能使用像
M2.y
Run Code Online (Sandbox Code Playgroud)
获得3除非我指定的模块
module M2 : S with type t = int = struct ...
Run Code Online (Sandbox Code Playgroud)
为什么会这样?已经有说法了type t = int
具体的,int值M2.y确实不可用,因为满足以下两个条件:
签名中的类型y是抽象的S
(没有type t = ...)
模块相对于签名M2是不透明的S
(换句话说,它仅限于S 通过符号的签名: S)
结果,您确实获得了:
let test = M2.y ;;
(* val test : M2.t = <abstr> *)
Run Code Online (Sandbox Code Playgroud)
正如关键字所建议的<abstr>,这与抽象类型的概念有关。这个概念是由 OCaml 的类型规则强制执行的一个非常强大的特性,它阻止具有签名的模块的任何用户S检查一个这样的抽象类型的具体内容。因此,通过仔细分离 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 *)
Run Code Online (Sandbox Code Playgroud)
但在实践中这不是很有趣,因为你失去了一般性。然而,一种更有趣的方法是在签名中添加一个“评估器”或“漂亮的打印机”函数,例如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 *)
Run Code Online (Sandbox Code Playgroud)
否则,如果模块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 *)
Run Code Online (Sandbox Code Playgroud)
最后,需要注意的是,除了抽象类型的特性之外,OCaml 还提供了私有类型的特性,可以将其视为模块化开发中使用的具体类型和抽象类型之间的权衡。有关此概念的更多详细信息,请参见例如章节。8 Caml ref man。