给定以下模块签名,其中B
包含A
:
module type A = sig
type t
end
module type B = sig
type t
val x: t
end
通常,任何满足 的模块B
也将满足A
。然而,这不会自动扩展到一流模块,因为它当然是一种不同的类型语言,不允许与子类型自动统一。但手动强制应该仍然有效,不是吗?(事实上,如果模块签名仅包含类型定义,则确实如此,但如果它包含值则不然。)
let f (_: (module A)) = ()
let g (b: (module B)) = f (b :> (module A)) (* Error: Type (module B) is not a subtype of (module A) *)
这是一流模块的基本限制吗?在核心类型语言中,确定一个模块类型是否是另一个模块类型的子类型的规则是什么?有没有实际的解决方法?
类型强制是 OCaml 中仅类型级别的操作。换句话说,它预计在运行时是无操作的。
为了保留此属性,第一类模块的子类型需要使用受限模块子类型关系:
(module A)
<:(module B)
当且仅当A<:B
两种模块类型的所有运行时组件出现在相同位置。例如,这很好:
因为两种模块类型都同意第一个运行时组件是
x
,第二个运行时组件是y
。恰恰相反x
失败,因为两种模块类型在字段和的位置上不一致y
。为了回答我自己关于实际解决方法的问题,当然可以解压并重新打包模块。在这个简单的例子中,这非常方便:
然而,当一流模块嵌入到某些数据结构中时,这有点不太方便。