我是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
如何使用这些批注而不引起编译错误?
答案 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