我为可格式化的集合创建了一个仿函数,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
实现这一点很简单:
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
Run Code Online (Sandbox Code Playgroud)
我想用地图做类似的事情. POrderedType适用于键,但我需要一个更简单的值类型:
module type Printable =
sig
type t
val format : Format.formatter -> t -> unit
end
Run Code Online (Sandbox Code Playgroud)
然后我想做类似于我为套装做的事情,但我遇到了以下问题. Map.S值有类型+'a t.我无法找到一种方法来包含Map.S定义,同时约束'a为a Printable.t.我想要的是以下内容(忽略它是非法的这一事实):
module MakeMap (Pkey : POrderedType) (Pval : Printable) :
MAP with type key = Pkey.t and type 'a t = 'a t constraint 'a = Pval.t
Run Code Online (Sandbox Code Playgroud)
有没有办法做我想要的而不用手工复制整个Map的签名?
我认为提出多态地图打印功能的最简洁方法是使地图打印功能参数化于值打印功能。你可以这样想:
函子定义的类型是在函子级别定义的,因此最好通过添加新函子参数(或丰富现有参数)来为它们提供函数
参数类型在值级别绑定(泛化),因此最好通过向值添加新参数来为它们提供函数
在 OCaml 中,方便性往往使人们在可能的情况下更喜欢参数多态而不是函子化。有时需要函子化来强制执行某种类型安全(这里它用于确保不同比较函数上的映射具有不兼容的类型),但除此之外,人们宁愿尝试具有多态性。所以你实际上处于幸运的境地。
如果你真的想让一个函子生成单态映射,那么,恐怕你将不得不复制整个映射接口并在单态情况下对其进行调整——这并不是什么工作。