假设这些:
module type Foo = sig
type t
val foo : t -> t
end
module M = struct
type t = int
let foo t = t + 1
end
然后我这样做:
module type Goo = Foo with type t = int
module type Hoo = Foo with type t := int
let x = (module M : Goo) (* correct *)
let y = (module M : Hoo) (* correct *)
let z = (module M : Foo with type t = int) (* correct *)
最重要的是,没问题。
然而,如果我这样做
let z = (module M : Foo with type t := int) (* wrong *)
这是错误的,并且给出了错误
错误:解析错误:" ="预期在[ident]之后(在[package_type_cstr]中)
为什么我无法在头等舱模块包装中使用:=
?
答案 0 :(得分:8)
在OCaml 4.01及更早版本中,第一类模块是名义上的类型。换句话说,它们的类型基于所使用的模块类型的名称,而不是其结构。例如:
OCaml version 4.01.0
# module type T = sig type t end;;
module type T = sig type t end
# module type S = sig type t end;;
module type S = sig type t end
# let f (x : (module T)) : (module S) = x;;
Characters 38-39:
let f (x : (module T)) : (module S) = x;;
^
Error: This expression has type (module T)
but an expression was expected of type (module S)
这要求模块类型具有名称:
# type t = (module sig type t end);;
Characters 17-20:
type t = (module sig type t end);;
^^^
Error: Syntax error
不允许破坏性替换,因为它会创建一个没有名称的新模块类型。定期替换很好,因为S with type t = int
仍然是S
,我们只是更了解它的定义。 S with type t := int
不是S
,它与S
的组件不同,因为它缺少t
类型。
最近(Mantis,SVN),对一流模块的类型检查已经改为结构而不是主格:
OCaml version 4.02.0+dev5-2014-04-29
# module type T = sig type t end;;
module type T = sig type t end
# module type S = sig type t end;;
module type S = sig type t end
# let f (x : (module T)) : (module S) = x;;
val f : (module T) -> (module S) = <fun>
这意味着可以为没有名称的类型创建第一类模块。但是,这还没有完成,将不会在4.02中提供。因此,在4.02之后的版本中,确实可以在第一类模块类型中使用破坏性替换。