OCaml使用在仿函数外部定义的签名来限制对生成的模块的可见性

时间:2017-09-29 17:21:37

标签: module ocaml encapsulation functor

我试图编写一个带有一对有序东西的仿函数,并生成另一个有序的东西(按字典顺序定义排序)。

但是,我希望得到的"有序类型"是抽象的,而不是OCaml元组。

这很容易与内联/匿名签名一起使用。

(* orderedPairSetInlineSig.ml *)

module type ORDERED_TYPE = sig
  type t
  val compare : t -> t -> int
end

module MakeOrderedPairSet (X : ORDERED_TYPE) :
  sig
    type t
    val get_fst : t -> X.t
    val get_snd : t -> X.t
    val make : X.t -> X.t -> t
    val compare : t -> t -> int
  end = struct
    type t = X.t * X.t

    let combine_comparisons fst snd =
      if fst = 0 then snd else fst

    let compare (x, y) (a, b) =
      let cmp  = X.compare x a in
      let cmp' = X.compare y b in
      combine_comparisons cmp cmp'

    let get_fst ((x, y) : t) = x

    let get_snd ((x, y) : t) = y

    let make x y = (x, y)
  end

我想给我的匿名签名一个像ORDERED_PAIR_SET_TYPE这样的名称,并将其移到MakeOrderedPairSet的定义之外,就像这样(警告:语法无效):

(* orderedPairSet.ml *)

module type ORDERED_TYPE = sig
  type t
  val compare : t -> t -> int
end

module type ORDERED_PAIR_SET_TYPE = sig
  type t
  type el

  val get_fst : t -> el
  val get_snd : t -> el
  val make : el -> el -> t

  val compare : t -> t -> int
end

module MakeOrderedPairSet (X : ORDERED_TYPE) :
  (ORDERED_PAIR_SET_TYPE with type el = X.t) = struct
    type t = X.t * X.t

    let combine_comparisons fst snd =
      if fst = 0 then snd else fst

    let compare (x, y) (a, b) =
      let cmp  = X.compare x a in
      let cmp' = X.compare y b in
      combine_comparisons cmp cmp'

    let get_fst ((x, y) : t) = x

    let get_snd ((x, y) : t) = y

    let make x y = (x, y)
  end

el是签名中的抽象类型,我试图绑定到X.t正文中的MakeOrderedPairSet

但是,我无法弄清楚如何将所有东西放在一起。

(ORDERED_PAIR_SET_TYPE with type el = X.t)是我能想到的最明显的方式"给我一个像这样的签名,但抽象类型被一个具体的(或不同的)取代 - 在这种情况下抽象)"。但是,在这种情况下,它在语法上无效(因为括号)。取下括号不会产生有效的"模块语言级表达式"要么;我把它留下来是因为我认为它使我的意图更加明显。

那么......你如何使用命名签名来限制[由仿函数生成的模块] / [参数化模块]的可见性?

1 个答案:

答案 0 :(得分:2)

If you don't want to add el to the exports of the module then there are two ways:

  1. Use a substitution constraint:

    ORDERED_PAIR_SET_TYPE with type el := X.t
    

    That will remove the specification of el from the signature.

  2. Use a parameterised signature. Unfortunately, that is not expressible directly in OCaml, but requires a bit of extra functor gymnastics around the definition of your signature:

    module SET_TYPE (X : ORDERED_TYPE) =
    struct
      module type S =
        sig
          type t
          val get_fst : t -> X.el
          val get_snd : t -> X.el
          val make : X.el -> X.el -> t
          val compare : t -> t -> int
        end
      end
    

    With that you can write:

    module MakeOrderedPairSet (X : ORDERED_TYPE) : SET_TYPE(X).S = ...