OCaml:类型声明中的Functor应用程序

时间:2015-04-27 21:58:36

标签: ocaml

我正在尝试使用声明中的类型参数来参数化仿函数。举个例子,假设我有以下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

有没有办法让这项工作?

2 个答案:

答案 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