我在 OCaml 中有非常简单的签名和模块:
module type S = sig
type t
val y : t
end;;
and
module M2 : S = struct
type t = int
let x = 1
let y = x+2
end;;
我不能使用像这样的构造
M2.y
to get 3
除非我将模块指定为
module M2 : S with type t = int = struct ...
为什么会这样呢?已经有声明说type t = int
混凝土,int
价值M2.y
确实不可用,因为满足以下两个条件:
-
的类型y
is abstract在签名中S
(没有type t = ...
there)
-
模块M2
被制作opaque关于签名S
(换句话说,仅限于签名S
via符号: S
)
结果,您确实获得了:
let test = M2.y ;;
(* val test : M2.t = <abstr> *)
正如关键字所建议的<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 *)
但实际上这并不是很有趣,因为你失去了一般性。然而,一种更有趣的方法是在签名中添加“评估器”或“漂亮打印机”功能,例如值int_of_t
below:
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 还提供了以下功能:私有类型这可以被视为模块化开发中使用的具体类型和抽象类型之间的权衡。有关此概念的更多详细信息,请参见示例章节。 8 骆驼裁判员.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)