将一个模块及其实例作为OCaml函数的参数

4

我希望编写一个函数,它接受实现某个签名的模块和与这些模块相同类型的实例作为参数。但是由于模块的作用域问题(模块和其实例都是参数),我似乎无法做到这一点,因此实例不知道模块的类型。

以下是一个示例:

let f (type a) (module M: Set.S with type elt = a) (pr: a -> unit) (m: M.t) = 
  M.iter pr m;;

M是一个由类型为a的元素构成的Set模块,pr可以用于打印类型为a的元素。下面是由此引起的错误信息(我认为不是非常清晰):

Line 1, characters 69-78:
Error: This pattern matches values of type M.t
       but a pattern was expected which matches values of type 'a
       The type constructor M.t would escape its scope

我试图通过考虑参数范围仅涵盖函数主体而导致问题的方式来解决这个问题,所以我将最后一个参数放在函数体内,像这样:

let f (type a) (module M: Set.S with type elt = a) (pr : a -> unit) =
  fun (m : M.t) ->
    M.iter pr m;;

但错误信息仍然存在:

Line 2, characters 7-16:
Error: This pattern matches values of type M.t
       but a pattern was expected which matches values of type 'a
       The type constructor M.t would escape its scope

那么有没有一种方法可以做到这一点?
1个回答

6

OCaml核心语言(模块系统之外)并不是依赖类型的。在幻想语法中,您的函数类型将是function <module M:Set.S with type elt = 'a> -> ('a -> unit) -> M.t。在这种类型中,M是一个值,因此该类型是依赖类型,无法在OCaml中实现。

在您的情况下,可以通过使用with约束来限制接受的模块类别,使类型不依赖于参数模块。

let f (type a t ) (module M: Set.S with type elt = a and type t = t)
  pr m = M.iter pr m
module String_set = Set.Make(String)
let () = f (module String_set) ignore String_set.empty 

另一个可能的解决方案是将值与第一类模块及其存在量化一起存储:


module type packed = sig
  type a
  module Impl: Set.S with type elt = a
  val value: Impl.t
end

let g (type a) (module P: packed with type a = a)
  pr = P.Impl.iter pr P.value

但对于更复杂的功能,只有在模块级别使用函数对象才是唯一的选择。

补充说明:如果你想知道为什么第一个变体中的模块类型 Set.S with type elt = a and type t = t 是(必要的)限制,可以考虑下面的打包模块:

let random_int_set: (module Set.S with type elt = int) =
  let compare =
     if Random.int 3 > 1 then Stdlib.compare
     else (fun x y -> Stdlib.compare y x)
  in
  let module S = Set.Make(struct type t = int let compare = compare end) in
  (module S)

这里,集合类型基于一个随机的compare函数。因此,这种集合类型与所有其他Set不兼容。因此,只能使用这个模块与打包的值一起使用:

module P = struct
  type a = int
  module Impl = (val random_int_set)
  let value = Impl.empty
end
let () = g (module P) ignore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接