我正在尝试使用声明中的类型参数来参数化仿函数。举个例子,假设我有以下GADT声明:
type _ basic =
| String : string -> string basic
| Integer : int -> int basic
我想使用Map.Make
来构建使用上述类型作为键类型的地图。由于我无法在type t = 'a basic
中免费提供类型变量,因此我需要一个仿函数将'a basic
转换为OrderedType
:
module OrderedBasic(Type : sig type tag end) :
(Map.OrderedType with type t = Type.tag basic) =
struct
type t = Type.tag basic
let compare : type a. a basic -> a basic -> int = fun b1 b2 ->
match b1, b2 with
| String s1, String s2 -> String.compare s1 s2
| Integer i1, Integer i2 -> compare i1 i2
end
我可以创建我想要的地图:
module OrderedBasicString = OrderedBasic(struct type tag = string end)
module BasicStringMap = Map.Make(OrderedBasicString)
并命名地图类型:
type 'v string_map = 'v BasicStringMap.t
但是,我想要做的是通过basic
的类型参数来参数化地图类型,例如:
type ('k, 'v) basic_map = 'v Map.Make(OrderedBasic(struct type tag = 'k end)).t
但似乎不允许这样做:我在内联struct
定义中遇到语法错误。最后,我想在另一个GADT中嵌入可以具有上述任何基本键类型的地图,如:
type _ data =
Map : 'a data Map.Make(OrderedBasic(struct type tag = 'b end)).t -> 'c data
有没有办法让这项工作?
答案 0 :(得分:3)
问题是Map
是在固定arity的关键类型上定义的,而arity是零。
如果你使用的仿函数允许你想要的arity,那很容易:
type _ basic =
| String : string -> string basic
| Integer : int -> int basic
module type INDEXED = sig
type 'a t
val equal : 'a t -> 'a t -> bool
end
module MakeAlist (Elt : INDEXED) = struct
type ('i, 'v) t = Nil | Cons of 'i Elt.t * 'v * ('i, 'v) t
let rec find elt = function
| Nil -> None
| Cons (x, v, xs) ->
if Elt.equal elt x then Some v
else find elt xs
(* etc *)
end
module BasicAlist = MakeAlist (struct
type 'a t = 'a basic
let equal : type a . a basic -> a basic -> bool = fun b1 b2 ->
match b1, b2 with
| String s1, String s2 -> s1 = s2
| Integer i1, Integer i2 -> i1 = i2
end)
type _ data = Map : ('a data, 'b) BasicAlist.t -> 'c data
我不会建议你用你想要的arity重新实现Map
,虽然这可以解决你的问题 - 可能有一些我不知道会让你重复使用的技巧Map
。
答案 1 :(得分:2)
您必须使用密钥类型中具有多态性的地图,例如map from core。
open Core.Std
module Basic = struct
type 'a t =
| String : string -> string t
| Int : int -> int t
let sexp_of_t : type a. a t -> Sexp.t = function
| String s -> String.sexp_of_t s
| Int i -> Int.sexp_of_t i
let compare : type a. a t -> a t -> int = fun b1 b2 ->
match b1, b2 with
| String s1, String s2 -> String.compare s1 s2
| Int i1, Int i2 -> compare i1 i2
end
module Cmp = Comparator.Make1(Basic)
type _ data =
Map : ('a Basic.t, 'b, Cmp.comparator_witness) Map.t -> 'c data