Map 将OCaml映射扩展到可格式化映射

Map 将OCaml映射扩展到可格式化映射,map,ocaml,functor,Map,Ocaml,Functor,我为可设置格式的集合制作了一个函子,如下所示: module type POrderedType = sig type t val compare : t -> t -> int val format : Format.formatter -> t -> unit end module type SET = sig include Set.S val format : Format.formatter -> t

我为可设置格式的集合制作了一个函子,如下所示:

module type POrderedType =
  sig
    type t
    val compare : t -> t -> int
    val format : Format.formatter -> t -> unit
  end

module type SET =
  sig
    include Set.S
    val format : Format.formatter -> t -> unit
  end

module MakeSet (P : POrderedType) : SET with type elt = P.t
实现这一点很简单:

module MakeSet (P : OrderedType) =
  struct
    include Set.Make(P)

    let format ff s =
      let rec format' ff = function
        | [] -> ()
        | [v] -> Format.fprintf ff "%a" format v
        | v::tl -> Format.fprintf ff "%a,@ %a" format v format' tl in
      Format.fprintf ff "@[<4>%a@]" format' (elements s)
  end
然后我想做一些类似于我为集合所做的事情,但我遇到了以下问题
Map.S
值的类型为
+'a t
。我无法找到一种方法来包含
Map.S
定义,同时将
'a
约束为
可打印的.t
。我想要的是以下内容(忽略这是非法的事实):


有没有什么方法可以在不手动复制地图的整个签名的情况下实现我想要的功能?

我认为为多态地图提出打印功能最干净的方法是使地图打印功能参数化,而不是值打印功能。你可以这样想:

  • 函子定义的类型是在函子级别定义的,因此为它们提供函数最好通过添加新的函子参数(或丰富现有参数)来完成

  • 参数化类型是在值级别绑定(通用)的,因此最好通过向值添加新参数来为其提供函数

在OCaml中,方便往往使人们在可能的情况下更喜欢参数多态性而不是函数化。函数化有时是强制执行某些类型安全性所必需的(这里它用于确保不同比较函数上的映射具有不兼容的类型),但在其他情况下,人们宁愿尝试使用多态性。所以你在这里真的很幸运

如果你真的想要一个函子生成单态映射,那么,恐怕你必须复制整个映射接口,并在单态情况下进行调整——这不是很多工作

module type Printable =
  sig
    type t
    val format : Format.formatter -> t -> unit
  end
module MakeMap (Pkey : POrderedType) (Pval : Printable) :
  MAP with type key = Pkey.t and type 'a t = 'a t constraint 'a = Pval.t