为啥 OCaml 中的模块类型注释会导致此代码无法编译?

Posted

技术标签:

【中文标题】为啥 OCaml 中的模块类型注释会导致此代码无法编译?【英文标题】:Why does a module type annotation in OCaml cause this code to not compile?为什么 OCaml 中的模块类型注释会导致此代码无法编译? 【发布时间】:2022-01-15 15:32:08 【问题描述】:

我正在使用 OCaml 中的 Map 模块。考虑以下代码来创建一个以整数为键的映射:

module Int = struct
    type t = int
    let compare a b = a - b
end
 
module IntMap = Map.Make(Int)

let m = IntMap.(empty |> add 3 "hello")

这一切都很好。它的编译和行为符合我的预期。

但是,如果我为 Int 模块添加类型注释,那么顶行变为:

module Int : Map.OrderedType = struct

最后一行导致编译出错:

let m = IntMap.(empty |> add 3 "hello")
                             ^
Error: This expression has type int but an expression was expected of type
         IntMap.key = Int.t

但是IntMap.keyInt.t 都只是int 的别名。此外,Int 模块的类型为Map.OrderedType。我知道这一点,因为这是 Map.Make 所需的类型。

那么地球在这里发生了什么?为什么提供不必要的类型注释会导致这样的错误。类型注释是否会导致更严格的可访问性并且与推断类型的行为不同?

【问题讨论】:

【参考方案1】:

这种注解严格限制了模块的接口。所以在我看来,添加注释后,关于地图键类型的唯一已知信息由Map.OrderedType 给出:

module type OrderedType =
    sig type t val compare : t -> t -> int end

这对t 类型没有任何说明,只是它存在并且出现在compare 的参数中。换句话说,您隐藏了t(也称为IntMap.key)类型与int 相同的事实。

您可以使用with 重新介绍这个事实:

module Int : Map.OrderedType with type t = int = struct
    type t = int
    let compare a b = a - b
end

【讨论】:

以上是关于为啥 OCaml 中的模块类型注释会导致此代码无法编译?的主要内容,如果未能解决你的问题,请参考以下文章

Ocaml 类型不匹配?预期单位,但为已定义类型

为啥 iife 中的包装函数会导致弱类型?

为啥此代码会生成类型注释警告?

Ocaml 值与模块和签名中的参数化类型不匹配

为啥此代码会导致 Excel 无法正常关闭?

OCaml中元组的类型注释