在函数签名中包含模块签名和该模块类型的值

Lho*_*ooq 2 polymorphism ocaml first-class-modules

我只想有一个在 Hashtbls 上通用的简单函数,所以我写了这个:

let iter_htbl (type a) (module H : Hashtbl.S with type key = a) htbl =
  H.iter (fun _key _v -> ()) htbl
Run Code Online (Sandbox Code Playgroud)

这给了我以下错误:

53 |   H.iter (fun _key _v -> ()) htbl
                                  ^^^^
Error: This expression has type 'a but an expression was expected of type
         'b H.t
       The type constructor H.t would escape its scope
Run Code Online (Sandbox Code Playgroud)

如果我写:

53 |   H.iter (fun _key _v -> ()) htbl
                                  ^^^^
Error: This expression has type 'a but an expression was expected of type
         'b H.t
       The type constructor H.t would escape its scope
Run Code Online (Sandbox Code Playgroud)

新错误(但几乎相同):

52 | let iter_htbl (type a b) (module H : Hashtbl.S with type key = a) (htbl : b H.t)
                                                                       ^^^^^^^^^^^^^^
Error: This pattern matches values of type b H.t
       but a pattern was expected which matches values of type 'a
       The type constructor H.t would escape its scope
Run Code Online (Sandbox Code Playgroud)

对于我想要实现的目标有解决方案吗?

当然,在我的简单情况下我可以写

let iter_htbl (type a b) (module H : Hashtbl.S with type key = a) (htbl : b H.t)
    =
  H.iter (fun _key _v -> ()) htbl
Run Code Online (Sandbox Code Playgroud)

但如果我想使用多个函数,H这不是一个有用的解决方案。

And*_*erg 5

那是行不通的。不幸的是,OCaml 的类型系统无法直接表达这一点。这将需要更高级的多态性,而 ML 核心语言不具备这一点:

\n
let iter_htbl (type key) (type 'a htbl) (type a) (module H : Hashtbl.S with type key = key with type 'a t = 'a htbl) (htbl : a htbl) = ...\n
Run Code Online (Sandbox Code Playgroud)\n

存在(type 'a htbl)语法错误 \xe2\x80\x93 是有原因的,因为参数化类型的这种多态性不能轻易地与类型推断相协调(至少在没有某些限制的情况下),因为它需要在一般情况,无法判定。

\n

在 ML 中抽象参数化类型(如 Ht)的唯一方法是提升到模块级别并编写函子:

\n
module IterHtbl (H : Hashtbl.S) (T : sig type a val htbl : a H.t end) =\nstruct\n  let it = H.iter (fun _ _ -> ()) T.htbl\nend\n
Run Code Online (Sandbox Code Playgroud)\n

这是可行的,因为模块的类型更加明确。

\n