2017-04-19 140 views
0

所以,当你定义模块的结构,它可以延长另一个模块关闭它:扩展递归模块

module Base = struct 
    type t = Name of string 
end 

module Child = struct 
    include Base 
end 

Child.Name "test" 
(* - : Child.t = Child.Name "test" *) 

然而,随着recursive modules using recursive signatures工作时,我遇到问题时,我尝试延长模块:

module rec Base : sig 
    type t = | Name of string 
end = Base 

and Child : sig 
    include Base 
end = Child 

当我这样做,我得到一个错误说:

Error: Unbound module type Base 

在使用此递归模块技巧时,您不能扩展模块吗?我误会了什么或做错了什么?

+0

我想补充一点,远离递归模块是个好主意。 –

+0

@ÉtienneMillon怎么回事?你有什么文章可以把我和这件事联系起来吗? –

+0

这被标记为实验性的,并且受到手册中的重大更改的影响,类型推断被降级,您不能将它们放在单独的文件中。我认为过去有健全的错误。打破递归或者在类型和值之间移动它几乎总是最好的解决方案。 –

回答

1

在我看来,你的问题是,Base是一个模块,而不是一个模块类型。当包含在sig ... end构造中时,您需要一个类型。当包含在struct ... end构造中时,您需要一个模块。这就是为什么第一个例子有效,而第二个例子没有。

如果我改变Basemodule type of Base我得到这个错误:

Error: Illegal recursive module reference 

所以我怀疑这个特殊的(有些奇怪)类型递归定义的不支持。

如果分别定义模块类型,你可以把它的工作:

module type BASE = sig type t = Name of string end 

module rec Base : BASE = Base 

and Child : sig 
    include BASE 
end = Child 
+0

这是有道理的;我无法在签名定义中包含模块的定义。谢谢Jeffrey –

+0

如果你不介意单独定义模块类型,你可以得到你想要的结构(见上文)。 –

0

杰弗里·斯科菲尔德已经给了很好的回答。我只想补充说include只是语法糖。因此,如果是include这会给您带来麻烦,解决方案可能是将其展开。在你的第一个例子中,将导致

module Base = struct 
    type t = Name of string 
end 

module Child = struct 
    type t = Name of string 
end 

显然,你的例子是你真正想做的简化版本。如图所示,根本不需要使用rec。所以我只能猜测你真的需要多少递归。根据Jeffrey Scofield的回答,recinclude的组合是有问题的。可能的是,摆脱include就足够了。