OCaml:类型构造函数转义其范围的问题

时间:2019-03-06 22:20:55

标签: types ocaml

代码如下:

module type S = sig
  type t
  val do_it: t -> int -> t
end

let rec foo (type a) (module Foo:S with type t=a) (i:int) (x:a) = 
  if i=0 then x
  else foo (i-1) (Foo.do_it x i)

我收到此类型错误(在第8行,字符17-32):

Error: This expression has type a but an expression was expected of type 'a
       The type constructor a would escape its scope

这是意外的,因为类型构造函数a仍在其范围内。我希望函数foo具有以下类型:

foo: (module S with type t = 'a) -> int -> 'a -> 'a

怎么了?

1 个答案:

答案 0 :(得分:3)

问题是多态递归:函数foo的主体在没有显式注释的情况下不能是多态的。写作时

let rec foo (type a) (module Foo:S with type t=a) (i:int) (x:a) = 
  if i=0 then x
  else foo (module Foo:S with type t = a) (i-1) (Foo.do_it x i)

由于函数foo的定义不是多态的,因此它无法重用在其自己的定义之后引入的局部抽象类型type a

规避此问题的一种方法是在局部抽象类型之后引入递归函数:

let foo (type a) =
  let rec foo (module Foo:S with type t=a) (i:int) (x:a) = 
  if i=0 then x
  else foo (module Foo) (i-1) (Foo.do_it x i) in
  foo

一种更为经典的解决方案是向本地抽象类型a添加一个显式的通用量化:

let rec foo: type a. (module S with type t=a) -> int -> a -> a =
fun (module Foo) i x ->
  if i=0 then x
  else foo (module Foo) (i-1) (Foo.do_it x i)