首页 > 解决方案 > OCaml:在 mli 文件中表达“t 集”

问题描述

OCaml 的新手和 Sets 的绊脚石(真的,模块类型和仿函数)。我想在.mli文件中定义以下内容:

type t

type tag

val tags : t -> <set of tag>

set of tag我无法弄清楚的类型在哪里,类似于tag list.

更新:感谢杰弗里斯科菲尔德在下面的有用评论,但由于我的真正问题仍未得到解答,我认为我表达得不好。这是第二次尝试:

鉴于此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 -> ???

where???表示“TagSet.t”,同时仍保持tag抽象,即“使用 t = 的 OrderedType 调用 Set.Make 的结果tag”。

这可能吗?似乎必须如此。我正在寻找 OCaml 最接近 Scala 的Set[T].

标签: setocaml

解决方案


在开始探索 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带有 type 元素的模块类型,那就太好了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 

推荐阅读