如何修复将类型注释与functor一起使用时出现的OCaml编译错误?

如何修复将类型注释与functor一起使用时出现的OCaml编译错误?,ocaml,functor,Ocaml,Functor,我是OCaml新手,我正在尝试使用函子。当我对functor使用模块类型注释时,这会导致代码中出现编译时错误 当我删除:Printable(从模块FromToString行)和:ToString(从模块IntToString行)注释时,以下程序编译无误: module type ToString = sig type t val to_string: t -> string end module type Printable = sig type t va

我是OCaml新手,我正在尝试使用函子。当我对functor使用模块类型注释时,这会导致代码中出现编译时错误

当我删除
:Printable
(从
模块FromToString
行)和
:ToString
(从
模块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

如何使用这些注释而不导致编译错误?

根本问题是您的签名约束使生成的模块过于不透明。约束函子结果时:

 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
它非常类似于
可打印
,只是现在类型
t
等于参数模块
S
的类型
t

因此,通过添加一个带有约束的
类型等式,可以重用
可打印的
来写入结果的完整模块类型:

  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

根本问题是签名约束使生成的模块过于不透明。约束函子结果时:

 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
它非常类似于
可打印
,只是现在类型
t
等于参数模块
S
的类型
t

因此,通过添加一个带有约束的
类型等式,可以重用
可打印的
来写入结果的完整模块类型:

  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

必须使用带有
符号的
将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

必须使用带有
符号的
将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