Ocaml 从模块签名中丢失类型精度
假设我有一个简单的模块Ocaml 从模块签名中丢失类型精度,ocaml,Ocaml,假设我有一个简单的模块MyFoo,看起来像这样 module MyFoo = struct type t = | A of string | B of int let to_string thing = match thing with | A str -> str | B n -> string_of_int n end 有了这个定义,它工作得很好,正如预期的那样-我可以做类似的事情 let _ = MyFoo.A "";; -
MyFoo
,看起来像这样
module MyFoo = struct
type t =
| A of string
| B of int
let to_string thing =
match thing with
| A str -> str
| B n -> string_of_int n
end
有了这个定义,它工作得很好,正如预期的那样-我可以做类似的事情
let _ = MyFoo.A "";;
- : MyFoo.t = MyFoo.A ""
没有任何问题
现在,也许我想创建一个使用这种结构的模块的函子,所以我定义了一个模块签名,它通常描述了这是什么样子,并称之为BaseFoo
module type BaseFoo = sig
type t
val to_string : t -> string
end
如果我以同样的方式重新定义MyFoo,但是给它这样的签名
module MyFoo : BaseFoo = struct
type t =
| A of string
| B of int
let to_string thing =
match thing with
| A str -> str
| B n -> string_of_int n
end
我失去了它的类型t
(有没有更好的方法来描述这里发生的事情?)-例如:
let _ = MyFoo.A "";;
Error: Unbound constructor MyFoo.A
这里到底发生了什么?为什么会发生?有没有一种规范的方法来处理这类问题(除了去掉签名之外)
我也尝试过手动包含签名和特定类型定义,但得到了另一种错误(这可能不是正确的方法)
你不需要签名
所发生的事情与您描述的差不多:给定MyFoo
其定义中的BaseFoo
签名将其限制为签名
为什么??因为这就是在这里指定签名的目的。规范的解决方案是保留签名(通常,让签名定义位于模块定义旁边对读者来说足够清晰)
请注意,当您在functor上调用MyFoo
时,将检查签名。我通常的选择是依靠这一点
一些变通办法
考虑到你所做的尝试,我想这可能会让你感兴趣:
module type BaseFoo = sig ... end
module MyFoo = struct ... end
module MyFooHidden : BaseFoo = MyFoo (* Same as defining MyFoo : BaseFoo *)
module MyFooWithType :
BaseFoo with type t = MyFoo.t
= MyFoo (* What you want *)
with type t=t'
子句允许您对模块签名进行注释,以向其添加类型信息。它非常有用,尤其是在处理函子时。有关更多信息,请参阅
MyFooHidden
可能看起来没用,但您可以将其视为检查MyFoo是否具有正确的签名。你仍然可以使用MyFoo
不管你想要什么MyFooWithType
实际上(有点)不太有用,因为如果您更改签名以添加希望导出的类型,您也需要在此处添加导出
使用包含
至于你的包括试试。好吧,很好的尝试!你就快到了:
module MyFoo : sig
type t = A of string | B of int
include BaseFoo with type t := t
end
类型为t:=t'
的有点不同,它不执行相等,而是执行替换。类型t
定义从BaseFoo
签名中删除,所有实例都替换为您自己的t
,这样您就不会出现任何双重定义问题。有关更多详细信息,请参阅
正如您所指出的,这可能不是您想要的方法,因为您不再容易知道MyFoo
确实是BaseFoo
module MyFoo : sig
type t = A of string | B of int
include BaseFoo with type t := t
end