在OCaml

时间:2015-07-03 13:56:22

标签: types module ocaml

我想为在给定模块中重用的构造函数定义一个类型别名,而不必通过它们定义它们的模块的路径作为前缀。我还想通过执行导入太多定义的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 Aopen A会在这里工作(RedBlue会有效),但两者都会向B添加定义,“污染”它

open会造成最小的伤害,但仍然会犯错误,例如如果A定义了由于B而在open中意外使用的符号,则不会出现编译错误。

有没有办法避免这种“污染”,同时阻止我在模块B中输入A.Red / A.Blue

3 个答案:

答案 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的答案很好。以下是另一种有时有用的方法:您可以定义三个模块,一个仅包含您的类型,然后是AB。打开AB中的第一个模块。