首页 > 解决方案 > 使 OCaml 模块签名显示它们的类型

问题描述

我有以下示例:

module type S = sig
  type t

  val do_something : t -> unit
end

module Foo : S = struct
  type t = [`Foo of int | `Bar of string]

  let do_something _ = ()
end

module Baz : S = struct
  type t = [`Baz of char | `Qux of unit]

  let do_something _ = ()
end


let () =
  Foo.do_something (`Foo 1);
  Baz.do_something (`Qux ())

但是在运行这个例子时,我得到:

File "./m.ml", line 21, characters 19-27:
Error: This expression has type [> `Foo of int ]
       but an expression was expected of type Foo.t

基本上,根据我的理解,它看起来S.t很抽象。. 让它“显化”的可能就是定义它。(例如type t = something。)

但问题是这种类型在Foo和之间变化Bar

有没有办法S.t在它的签名中体现出来,而不知道它的价值是什么?

标签: typesmoduleocaml

解决方案


问题确实是签名约束

module Baz : S = struct
  type t = [`Baz of char | `Qux of unit]
  let do_something _ = ()
end

使类型Baz.t抽象。此外,这会使模块Baz变得无用,因为没有办法产生 type 的值Baz.t

最简单的解决方案是删除签名约束。如果您还记得签名约束仅删除信息并且模块的类型是结构化的,这就不那么令人惊讶了。特别是,这意味着

 module Do_twice(X:S) = struct
   let do_twice x = X.do_something x; X.do_something x
 end
 module Baz = struct
   type t = [`Baz of char | `Qux of unit]
   let do_something _ = ()
 end
 module Twice_Baz= Do_twice(Baz)
 let () = Twice_Baz.do_twice (`Baz 'a')

按预期工作。

如果你想有一个明确的签名约束,你需要小心不要删除任何有用的信息。正确的做法是在带有约束t的模块类型中添加有关类型的更多信息:Swith

 module Baz: S with type t = [`Baz of char | `Qux of unit]  = struct
   type t = [`Baz of char | `Qux of unit]
   let do_something _ = ()
 end

推荐阅读