在 OCaml 中没有 "polluting" 模块的类型构造函数别名
Type constructor aliases without "polluting" a module in OCaml
我想为要在给定模块中重用的构造函数定义一个类型别名,而不必在定义它们的模块的路径前加上前缀。我还想通过执行 open
/include
来避免 "polluting" 后一个模块,因为它会导入太多定义。
这是我想要的示例(无法编译):
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 添加定义,"polluting"它。
open
会造成最少的伤害,但仍然允许犯错误,例如如果 A
定义了一个由于 open
而在 B
中意外使用的符号,我不会出现编译错误。
有没有办法避免这种情况"pollution",同时又能避免我在模块 B 中键入 A.Red
/A.Blue
?
是的。
您可以在 B
中定义 t
时声明它等于 A.t
并重写其构造函数列表:
module B = struct
type t = A.t = Red | Blue
let f = function
| Red -> 1
| Blue -> 0
end
类型检查器将验证定义与 A
中的定义完全相同,因此即使您修改了 A 中的类型定义,您也会被提醒在 B
中进行更改(是的,您输入了两次相同的内容,但这是一个简单的愚蠢 copy/paste).
@PatJ 的回答很好。这是另一种有时有用的方法:您可以定义三个模块,一个只包含您的类型,然后是 A
和 B
。打开 A
和 B
.
中的第一个模块
使用 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]
从同一个源文件中输入类型。引入的类型需要在单独的编译单元中定义。
我想为要在给定模块中重用的构造函数定义一个类型别名,而不必在定义它们的模块的路径前加上前缀。我还想通过执行 open
/include
来避免 "polluting" 后一个模块,因为它会导入太多定义。
这是我想要的示例(无法编译):
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 添加定义,"polluting"它。
open
会造成最少的伤害,但仍然允许犯错误,例如如果 A
定义了一个由于 open
而在 B
中意外使用的符号,我不会出现编译错误。
有没有办法避免这种情况"pollution",同时又能避免我在模块 B 中键入 A.Red
/A.Blue
?
是的。
您可以在 B
中定义 t
时声明它等于 A.t
并重写其构造函数列表:
module B = struct
type t = A.t = Red | Blue
let f = function
| Red -> 1
| Blue -> 0
end
类型检查器将验证定义与 A
中的定义完全相同,因此即使您修改了 A 中的类型定义,您也会被提醒在 B
中进行更改(是的,您输入了两次相同的内容,但这是一个简单的愚蠢 copy/paste).
@PatJ 的回答很好。这是另一种有时有用的方法:您可以定义三个模块,一个只包含您的类型,然后是 A
和 B
。打开 A
和 B
.
使用 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]
从同一个源文件中输入类型。引入的类型需要在单独的编译单元中定义。