0

我有一个仿函数,它的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)

4

2 回答 2

2

您可以构造新的签名来指定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)
于 2022-01-22T22:58:52.173 回答
1

Ok, after a couple of hours more fumbling around in the dark I found a recipe that does everything I wanted...

First we define a "showable" type, representing a module type that has had [@@deriving show] (from https://github.com/ocaml-ppx/ppx_deriving#plugin-show) applied to it:

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

(I don't know if there's some way to get this directly from ppx_deriving.show without defining it manually?)

Then we re-define and extend the Set and Set.OrderedType (i.e. element) types to require that the elements are "showable":

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

I think with the original code in my question I had got confused and used some kind of higher-order functor syntax (?) ...I don't know how it seemed to work at all, but at some point I realised my MySet_Make was returning a functor rather than a module. So we'll fix that now and just use a normal functor.

The other thing we can fix is to make MySet a further extension of ShowableSet ... so MySet_Make will take the element type as a parameter instead of another Set type. This makes the eventual code all simpler too:

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

Then we just need an OrderedShowable version of Int as the element type. Int is already ordered so we just have to extend it by deriving "show" and then we can make a concrete MySet:

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

module MyIntSet = MySet_Make(Int')

And we can use it like:

# let myset = MyIntSet.of_list [3; 2; 8];;
# print_endline (MyIntSet.show_el 3);;
"3"
于 2022-01-23T09:57:01.783 回答