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
获取此推断模块类型)。
从这一点开始,我们可以删除信息以使类型 tag
和 t
抽象:
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
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
获取此推断模块类型)。
从这一点开始,我们可以删除信息以使类型 tag
和 t
抽象:
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