6

我为可格式化的集合制作了一个仿函数,如下所示:

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

我想用地图做类似的事情。 POrderedType对键很好,但我需要一个更简单的值类型:

module type Printable =
  sig
    type t
    val format : Format.formatter -> t -> unit
  end

然后我想做一些类似于我为集合所做的事情,但我遇到了以下问题。 Map.S值有类型+'a t。我想不出一种方法来包含Map.S定义,同时将其限制'aPrintable.t. 我想要的是以下内容(忽略它是非法的事实):

module MakeMap (Pkey : POrderedType) (Pval : Printable) :
  MAP with type key = Pkey.t and type 'a t = 'a t constraint 'a = Pval.t

有什么方法可以在不手动复制 Map 的整个签名的情况下做我想做的事情?

4

1 回答 1

3

我认为为多态地图提出打印功能的最简洁方法是使地图打印功能参数化于值打印功能。你可以这样想:

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

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

在 OCaml 中,便利性往往使人们在可能的情况下偏爱参数多态性而不是函数化。函数化有时对于强制执行某种类型安全是必要的(这里它用于确保不同比较函数上的映射具有不兼容的类型),但除此之外人们宁愿尝试具有多态性。所以你在这里实际上是幸运的。

如果你真的想要一个生成单态地图的函子,那么,恐怕你将不得不复制整个地图界面并在单态情况下对其进行调整——这并不需要太多工作。

于 2012-10-15T05:44:50.327 回答