如何将 [@@deriving show] 应用于我的仿函数的模块参数中的类型?

How to apply [@@deriving show] to a type from module parameter of my functor?

我有一个采用 Set 类型的仿函数,例如:

module type MySet = functor (S : Set.S) -> sig
  val my_method : S.t -> S.elt -> S.elt list option
end

module MySet_Make : MySet = functor (S : Set.S) -> struct
  let my_method set el = Some [el]  (* whatever *)
end

module IntSet = Set.Make(Int)
module MyIntSet = MySet_Make(IntSet)

S.elt是集合的元素类型

我想以某种方式在我的仿函数中将 [@@deriving show](从 https://github.com/ocaml-ppx/ppx_deriving#plugin-show)应用到 S.elt,这样在我的一种方法中我可以依赖 show : S.elt -> string 功能可用。

我觉得这一定是可能的,但我想不出正确的语法。

或者 - 如果有一种方法可以在签名中指定 Set 类型 S 具有“可显示”类型的元素。

例如我可以定义:

module type Showable = sig
  type t [@@deriving show]
end

...但我不知道如何将其指定为 (S : Set.S)

元素的类型约束

您可以构造新的签名来指定您需要的确切功能show

module MySet_Make(S : sig
  include Set.S
  val show : elt -> string
end) = struct
  let my_method _set el =
    print_endline (S.show el);
    Some [el]
end

然后您可以通过构建具有所需功能的模块来构建实际的模块实例:

module IntSet = struct
  include Set.Make(Int)

  (* For other types, this function could be created by just using [@@deriving show] *)
  let show = string_of_int
end
module MyIntSet = MySet_Make(IntSet)

好的,在黑暗中又摸索了几个小时后,我找到了一个可以满足我所有需求的食谱...

首先我们定义一个“可显示”类型,表示已应用 [@@deriving show](来自 https://github.com/ocaml-ppx/ppx_deriving#plugin-show)的模块类型:

module type Showable = sig
  type t
  val pp : Format.formatter -> t -> unit
  val show : t -> string
end

(不知道有没有办法不用手动定义直接从ppx_deriving.show获取?)

然后我们 re-define 并扩展 SetSet.OrderedType(即元素)类型以要求元素是“可显示的”:

module type OrderedShowable = sig
  include Set.OrderedType
  include Showable with type t := t
end

module ShowableSet = struct
  include Set
  module type S = sig
    include Set.S
  end
  module Make (Ord : OrderedShowable) = struct
    include Set.Make(Ord)
  end
end

我认为我对问题中的原始代码感到困惑并使用了某种 higher-order 仿函数语法(?)...我根本不知道它是如何工作的,但是在某些时候我意识到我的 MySet_Make 正在返回一个仿函数而不是一个模块。所以我们现在就解决这个问题,只使用一个普通的仿函数。

我们可以解决的另一件事是使 MySet 成为 ShowableSet 的进一步扩展...因此 MySet_Make 将把元素类型作为参数而不是另一种 Set 类型.这也使最终代码更加简单:

module type MySet = sig
  include ShowableSet.S
  val my_method : t -> elt -> elt list option
  val show_el : elt -> string
end

module AdjacencySet_Make (El : OrderedShowable) : AdjacencySet
  with type elt = El.t
= struct
  include ShowableSet.Make(El)
  let my_method set el = Some [el]  (* whatever *)
  let show_el el = El.show el  (* we can use the "showable" elements! *)
end

那么我们只需要 IntOrderedShowable 版本作为元素类型。 Int 已经被订购了,所以我们只需要通过派生“show”来扩展它,然后我们就可以制作一个具体的 MySet:

module Int' = struct
  include Int
  type t = int [@@deriving show]
end

module MyIntSet = MySet_Make(Int')

我们可以像这样使用它:

# let myset = MyIntSet.of_list [3; 2; 8];;
# print_endline (MyIntSet.show_el 3);;
"3"