types - 使 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
在它的签名中体现出来,而不知道它的价值是什么?
解决方案
问题确实是签名约束
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
的模块类型中添加有关类型的更多信息:S
with
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
推荐阅读
- node.js - 如何解决在节点中将循环结构转换为 JSON?
- neo4j - 除一个节点外的最短路径
- php - Guzzle Post Request 发送带有附加参数的文件
- docker - nextjs 多级 docker 构建在 nginx 代理后面
- shiny - rCharts 蜘蛛网图在 Shiny 中呈现为线图
- python - 重复标志错误:标志被定义了两次:第一次在包中,第二次在包内的模块中
- c# - 在 C# 中使用 SendMessage() 写入 Excel
- python - pytz US/Eastern 来回转换时间戳
- javascript - 导出数组 Javascript
- r - 如何在 R 中使用“'try”来跳过 for 循环中的错误