我想为在给定模块中重用的构造函数定义一个类型别名,而不必通过它们定义它们的模块的路径作为前缀。我还想通过执行导入太多定义的open
/ include
来避免“污染”后一个模块。
这是我想要的一个例子(不编译):
module A = struct
type t = Red | Blue
end
module B = struct
type t = A.t
let f = function
| Red -> 1 (*Error: Unbound constructor Red*)
| Blue -> 0
let
end
在B中执行include A
或open A
会在这里工作(Red
和Blue
会有效),但两者都会向B添加定义,“污染”它
open
会造成最小的伤害,但仍然会犯错误,例如如果A
定义了由于B
而在open
中意外使用的符号,则不会出现编译错误。
有没有办法避免这种“污染”,同时阻止我在模块B中输入A.Red
/ A.Blue
?
答案 0 :(得分:7)
是的。
在t
中定义B
时,您可以声明它等于A.t
并重写其构造函数列表:
module B = struct
type t = A.t = Red | Blue
let f = function
| Red -> 1
| Blue -> 0
end
类型检查器将验证定义与A
中的定义完全相同,因此即使您在A中修改了类型定义,也会提醒您在B
中更改它(是的,你键入两次相同的东西,但这是一个简单的哑巴复制/粘贴)。
答案 1 :(得分:3)
使用OCaml 4.02.x及更高版本,您可以使用ppx_import(https://github.com/whitequark/ppx_import)。
a.ml
type t = A | B
b.ml
(* This gives a similar result to PatJ's answer *)
type a_t = [%import: A.t]
let foo = function
| A -> 0
| B -> 1
它不如PatJ的建议方法明确。如果您正在使用大型定义或A.t
在开发过程中频繁更改,则ppx可能会更简单。
ppx方法的缺点是你不能在同一个源文件中输入[%import]
个类型。导入的类型需要在单独的编译单元中定义。
答案 2 :(得分:1)
@PatJ的答案很好。以下是另一种有时有用的方法:您可以定义三个模块,一个仅包含您的类型,然后是A
和B
。打开A
和B
中的第一个模块。