结合使用带有函子的类型注释时,如何解决OCaml编译错误?

时间:2019-01-18 08:57:24

标签: ocaml functor

我是OCaml的新手,我正在尝试使用仿函数。当我将模块类型注释与函子一起使用时,这会导致我的代码出现编译时错误。

当我删除: Printable行中的module FromToString: ToString行中的module IntToString注释时,下面的程序编译没有错误:

module type ToString =
sig
    type t
    val to_string: t -> string
end

module type Printable =
sig
    type t
    val print: t -> unit
end

module FromToString (S:ToString) : Printable  =
struct
    type t = S.t
    let print a = print_string ( S.to_string a) 
end

module IntToString : ToString =
struct
    type t = int
    let to_string = string_of_int
end

module PrintableInt = FromToString(IntToString)
let () = PrintableInt.print 3

但是,当我添加这些注释(如代码中所示)时,编译器会出现以下错误:

File "Functor.ml", line 26, characters 28-29:
Error: This expression has type int but an expression was expected of type
         PrintableInt.t = FromToString(IntToString).t

如何使用这些批注而不引起编译错误?

2 个答案:

答案 0 :(得分:1)

根本问题是签名限制使生成的模块变得非常不透明。当您限制函子结果时:

 module FromToString (S:ToString) : Printable = ...

您正在将类型t作为抽象类型,该类型只能由to_string函数使用,并且永远不会产生。换句话说,Printable类型的模块本身无法使用。

从functor开始时,查看编译器为所得模块推断的模块类型通常很有用。 在FromToString情况下,这是:

module FromToString (S:ToString) : sig
  type t = S.t
  val print: t -> unit
end = ...

您可以看到结果的推断模块类型

 sig
   type t = S.t
   val print: t -> unit
 end

它与Printable非常相似,只不过现在类型t等于参数模块t的类型S

因此,可以通过添加具有Printable约束的类型相等性来重用with来写结果的完整模块类型:

  module FromToString (S:ToString): Printable with type t = S.t = struct
    type t = S.t
    let print a = print_string ( S.to_string a) 
  end

IntToString出现相同的问题,可以通过类似的方式解决:

module IntToString : ToString with type t = int =
struct
    type t = int
    let to_string = string_of_int
end

然后编译器错误消失了:

module PrintableInt = FromToString(IntToString)
let () = PrintableInt.print 3

答案 1 :(得分:0)

必须使用with表示法将t类型公开:

module type ToString =
sig
    type t
    val to_string: t -> string
end

module type Printable =
sig
    type t
    val print: t -> unit
end

module FromToString (S:ToString) : Printable with type t = S.t =
struct
    type t = S.t
    let print a = print_string ( S.to_string a) 
end

module IntToString : ToString with type t =int  =
struct
    type t = int
    let to_string = string_of_int
end

module PrintableInt = FromToString(IntToString)
let () = PrintableInt.print 3