将类型注释与仿函数一起使用时如何修复 OCaml 编译错误?
How to fix the OCaml compile error when using type annotations with functors?
我是 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
如何在不导致编译错误的情况下使用这些注释?
根本问题是您的签名约束使生成的模块过于不透明。当你约束你的仿函数结果时:
module FromToString (S:ToString) : Printable = ...
您正在使类型 t
成为抽象类型,它只能由 to_string
函数使用并且永远不会生成。换句话说,Printable
类型的模块本身是不可用的。
从仿函数开始时,查看编译器为生成的模块推断出的模块类型通常很有用。
在 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
等于参数模块 S
的类型 t
。
因此,可以重用 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
必须使用 with
表示法来制作类型 t public:
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
我是 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
如何在不导致编译错误的情况下使用这些注释?
根本问题是您的签名约束使生成的模块过于不透明。当你约束你的仿函数结果时:
module FromToString (S:ToString) : Printable = ...
您正在使类型 t
成为抽象类型,它只能由 to_string
函数使用并且永远不会生成。换句话说,Printable
类型的模块本身是不可用的。
从仿函数开始时,查看编译器为生成的模块推断出的模块类型通常很有用。
在 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
等于参数模块 S
的类型 t
。
因此,可以重用 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
必须使用 with
表示法来制作类型 t public:
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