有没有办法在类型上参数化模块或从OCaml中的模块中转义类型?

时间:2015-08-19 05:00:47

标签: ocaml locally-abstract-type

有没有办法在类型上参数化模块或从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返回暴露类型的方法。如果可能的话,我不想在REAL模块中使用另一个函数来转换t->float。我想以某种方式暴露实际类型t。另外,我想通过在本地使用模块而不是在REAL上参数化的仿函数来实现此目的。

1 个答案:

答案 0 :(得分:3)

您对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