OCaml:在 mli 文件中表达 "set of t"

OCaml: Expressing "set of t" in mli file

OCaml 的新手并且对 Sets(真的,模块类型和函子)有一些了解。我想在 .mli 文件中定义以下内容:

type t

type tag

val tags : t -> <set of tag>

其中 set of tag 是我无法弄清楚的类型,类似于 tag list.

更新:感谢 Jeffrey Scofield 在下面提供的有用评论,但由于我的真正问题仍未得到解答,我认为我表达得不好。这是第二次尝试:

鉴于此 a.ml

type tag = string

module TagSet = Set.Make (struct
  type t = tag
  let compare = String.compare
end)

type t = { name : string; tags : TagSet.t }

let empty = { name = ""; tags = TagSet.empty }

let get_tags { tags; _ } = tags

如何填写a.mli

type t

type tag

val empty : t

val get_tags : t -> ???

其中 ??? 表示“TagSet.t”,同时仍保持 tag 抽象,即“使用 t = [=20= 的 OrderedType 调用 Set.Make 的结果]".

这可能吗?看来必须如此。我正在寻找 OCaml 与 Scala 的 Set[T].

最接近的东西

您可以在您的接口中定义抽象参数化类型'a set

type t
type tag
type 'a set
val tags : t -> tag set

编写 .ml 文件时,您必须确定 'a set 的表示和实现。即,您需要提供一个可以包含任何元素类型的集合。

您也可以只有两种抽象类型,一种用于标签,一种用于一组标签:

type t
type tag
type tagset
val tags : t -> tagset

当您为此编写 .ml 文件时,您只需要实现一组标签(这可能比一般集合更有效)。

在开始探索OCaml的模块系统时,从编译器自身直接推断出的模块类型入手,逐步修改以更好地满足您的需要是非常有用的。

例如,从您的实现中推断出的模块是:

type tag = string
module TagSet :
  sig
    type elt = tag
    type t
    val empty : t
    ...
    val add_seq : elt Seq.t -> t -> t
    val of_seq : elt Seq.t -> t
  end
type t = { name : tag; tags : TagSet.t; }
val empty : t
val get_tags : t -> TagSet.t 

(您可以从 Merlin、ocaml-lsp、utop 或 ocamlc -i path_to_file.ml 获取此推断模块类型)。

从这一点开始,我们可以删除信息以使类型 tagt 抽象:

type tag
type t
module TagSet :
  sig
    type elt = tag
    type t
    val empty : t
    ...
    val add_seq : elt Seq.t -> t -> t
    val of_seq : elt Seq.t -> t
  end
val empty : t
val get_tags : t -> TagSet.t 

然后另一个问题是 TagSet 的模块类型相当大和冗长。能够将此签名定义为 Set 的模块类型和 tag 类型的元素会很好。幸运的是,模块 Set 定义了一个命名签名 S,正是出于这个原因,它描述了 Make 结果的签名。如果我们使用这个预定义的签名,我们可以将之前的定义简化为

type tag
type t
module TagSet : Set.S with type elt = tag
val empty : t
val get_tags : t -> TagSet.t