Ocaml 如何在两组不同(但重叠)和类型之间进行集合并集

Ocaml 如何在两组不同(但重叠)和类型之间进行集合并集,ocaml,Ocaml,我正在为编译器实现 以下是第一个集合和后续集合元素的类型定义: type first_set_element = | Terminal of terminal | Epsilon [@@deriving show, sexp] type follow_set_element = | Terminal of terminal | EndSymbol [@@deriving show, sexp] 如您所见,“终端”是两者之间的重叠变体 我希望能够得到一个FollowSet和一

我正在为编译器实现

以下是第一个集合和后续集合元素的类型定义:

type first_set_element =
  | Terminal of terminal
  | Epsilon [@@deriving show, sexp]

type follow_set_element =
  | Terminal of terminal
  | EndSymbol [@@deriving show, sexp]

如您所见,“终端”是两者之间的重叠变体

我希望能够得到一个FollowSet和一个FirstSet的并集,然后减去FirstSet的ε,这样结果仍然是FollowSet

当然,“简单”的解决方案是编写一个函数,将第一个集合转换为FollowSet,然后使用
FollowSet.union
。理想情况下,我将能够不重新实现集合操作。我很好奇OCaml类型系统中是否有什么东西,或者是否有更好的设计来解决这个问题

可能就是我要找的

以下是我如何定义集合:


module FirstSetElement = struct
  type t = first_set_element
  let compare a b = match (a, b) with
    | (Terminal(a), Terminal(b)) -> String.compare a b
    | (Terminal(_), Epsilon) -> 1
    | (Epsilon, Terminal(_)) -> -1
    | (Epsilon, Epsilon) -> 0
  let sexp_of_t t = sexp_of_first_set_element t
  let t_of_sexp t = first_set_element_of_sexp t
end

module FirstSet = Set.Make(FirstSetElement)

module FollowSetElement = struct
  type t = follow_set_element
  let compare a b = match (a, b) with
    | (Terminal(a), Terminal(b)) -> String.compare a b
    | (Terminal(_), EndSymbol) -> 1
    | (EndSymbol, Terminal(_)) -> -1
    | (EndSymbol, EndSymbol) -> 0
  let sexp_of_t t = sexp_of_follow_set_element t
  let t_of_sexp t = follow_set_element_of_sexp t
end

module FollowSet = Set.Make(FollowSetElement)

是的,多态变体有帮助。他们正是为了完成这样的任务。 下面是一个简单的例子:

a型=
[`A
|`Shared of int]
b型=
[`B
|`Shared of int]
设a=[`a;`Shared 1]
(*a:-[>`a |`Shared of int]list*)
设b=[`b;`Shared 2]
(*b:-[>`b |`Shared of int]list*)
设c=a@b
(*c:-[>`A |`B |`Shared of int]list*)
您可以通读手册以了解更多详细信息。
主要缺点是,您会得到更详细的类型,如上所示。

如果它们的形状和行为完全相同,为什么它们会不同?它只是为
Epsilon
/
EndSymbol
构造函数提供一个更有意义的名称吗?如果是这样的话,我会说你应该把数据结构抽象出来。使用公共数据结构,但将其隐藏并公开显式构造函数和操作。