如何解决将模块及其实例作为 OCaml 函数的参数
我想编写一个函数,该函数采用实现特定签名的模块和与这些模块相同类型的实例,但显然我不能这样做,因为与模块的范围(模块和它的实例都是参数,因此实例不知道模块的类型)。
这是一个例子:
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
那么有没有办法做到这一点?
解决方法
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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。