有没有一种方法可以在类型上参数化模块或从 OCaml 中的模块中转义类型?

Is there a way to parametrize a module on a type or escape a type from a module in OCaml?

有没有办法在 OCaml 中对类型的模块进行参数化或从模块中转义类型?基本上,我想编写一些在浮点类型上进行参数化的例程,并且仍然可以访问 (+.)、(-.) 等运算符。当然,我们可以编写一个浮点模块,如

module type REAL = sig
    type t
    val real : float->t
    val (+.) : t->t->t
    val (-.) : t->t->t
    val ( *. ) : t->t->t
    val (/.) : t->t->t
end

它对普通浮点数有一个非常基本的实现

module MyReal : REAL = struct
    type t=float
    let real x=x
    let (+.) x y = x+.y  
    let (-.) x y = x-.y
    let ( *. ) x y = x*.y
    let (/.) x y = x/.y
end

然后,我尝试在代码为

的模块中本地使用这个模块
let double (type real) (module Real:REAL with type t = real) x =
    let open Real in
    x+.x

这个函数有我想要的类型

val double : (module REAL with type t = 'a) -> 'a -> 'a = <fun>

但是,如果我运行它,编译器会报错

# double (module MyReal) 1.0;;
Error: This expression has type float but an expression was expected of type
         MyReal.t

当然,我们可以使用模块中的注入功能

# double (module MyReal) (MyReal.real 1.0);;
- : MyReal.t = <abstr>

但是结果类型是抽象的而不是浮点数。最终,我想要一种使函数 double return 成为公开类型的方法。如果可能的话,我不想在 REAL 模块中使用另一个函数来转换 t->float。我希望以某种方式公开实际类型 t。另外,我想要一种通过在本地使用模块而不是在 REAL.

上参数化的仿函数来执行此操作的方法

您给 MyReal 的类型约束过于严格:MyReal : REAL。它的类型 t 的实现被约束隐藏了。在使用 MyRealdouble (module MyReal) 1.0 时,类型 tfloat 的统一失败,因为您隐藏了事实 t = float.

修复如下:

module MyReal : REAL with type t = float = struct
  ...
end

但最好的方法是让 OCaml 自己推断 MyReal 的最一般类型:

module MyReal = struct
  ...
end

在这里,MyRealREAL 的关系不太清楚,但 OCaml 的模块类型足够聪明,可以找到 MyReal 有一个 module REAL with type t = 'a 的实例。