【问题标题】:Using .mli files and Map使用 .mli 文件和地图
【发布时间】:2017-02-19 19:24:05
【问题描述】:

我已经阅读了一些类似的问题和一些在线示例,但我仍然不知道在这种特殊情况下如何编写.mli 文件。

在我的项目中,我使用了一个带有 int 键的通用映射模块,然后我根据我想要存储的值进行专门化。假设我想用它来存储对,所以我有一个这样的文件:

file dataStr.ml:

module IntOrder =
   struct
      type t = int
      let compare = Pervasives.compare
   end

module IntMap = Map.Make( IntOrder )

type couple = int * int
(* pretty names *)
type int2couple = couple IntMap.t
module Couples = struct type t = int2couple end

使用这个子模块的文件是:

file useMap.ml:

open DataStr

let use k m =
   IntMap.add k ((Random.int 6), (Random.int 8)) m

带接口:

file useMap.mli:

open DataStr

val use : int -> Couples.t -> Couples.t

到目前为止,一切都很好。

现在假设我想公开子模块Couples,但不输入int2couple。然后我会写这个接口:

file dataStr.mli:

module IntMap : Map.S with type key = int

module Couples : sig type t end
(*
I'd like to avoid the redundancy of using
module Couples : sig type t = (int * int) IntMap.t end
*)

问题是,如果我添加这个接口,我会得到这个编译错误:

Error: The implementation useMap.ml does not match the interface useMap.cmi:
       Values do not match:
         val use :
           DataStr.IntMap.key ->
           (int * int) DataStr.IntMap.t -> (int * int) DataStr.IntMap.t
       is not included in
         val use : int -> DataStr.Couples.t -> DataStr.Couples.t

除了评论中的“冗余”接口之外,有没有办法编写一个让我做我想做的事情的接口?

【问题讨论】:

  • 如果你封装了(int * int) IntMap.t这个类型,在DataStr之外就没法知道那真的是一张地图。
  • 我猜这个级别的封装并没有太大的作用。你想对客户端代码隐藏什么?
  • 我只想显示“Couples”,同时隐藏“int2couple”和可能的“couple”,因为我创建它们只是为了使用它们dataStr.ml。除了界面可读性之外,我想要获得什么没有特别的原因。
  • 在这种情况下你可以暴露module Couples = struct type t = (int * int) IntMap.t end
  • 是的,正如我所写,我想避免在定义 (dataStr.ml) 和接口 (dataStr.mli) 中重复像 (int * int) IntMap.t 这样的语句,但我想这是唯一的选择。它仍然让我可以使用这些类型的 Map 为文件编写“更简单”的接口,例如 val use : int -> Couples.t -> Couples.t。如果您愿意,可以将您的 cmets 合并到一个答案中,我会将其标记为最佳。我真的不相信会出现其他解决方案。谢谢你的建议!

标签: dictionary types interface ocaml


【解决方案1】:

如 cmets 中所述,在实例化函子时,无法避免接口(mli 文件)和实现(ml 文件)之间的冗余。

您可以做的最好的事情是:

$ cat dataStr.mli:

module IntMap : Map.S with type key = int
type couple = int * int
type int2couple = couple IntMap.t
module Couples : sig type t = int2couple end

$ cat dataStr.ml:

module IntOrder =
  struct
      type t = int
      let compare = Pervasives.compare
  end

module IntMap = Map.Make( IntOrder )

type couple = int * int
type int2couple = couple IntMap.t
module Couples = struct type t = int2couple end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多