我不明白为什么OCaml无法弄清楚这里没有混淆的空间:下面的aint不能是A的另一个。
module A = struct
type test = Graphics.status
end
module type ASIG = sig
type test = A.test
val atest : test
end
module Func (H : ASIG) = struct
let _ = let open H in atest.key
end
然而,它提出了
Warning 40: key was selected from type Graphics.status.
It is not visible in the current scope, and will not
be selected if the type becomes unknown.
如何在不禁用警告的情况下告诉它“没关系”?
我知道我可以通过打开A
来解决它。但是,如果H将其自己的函数和类型定义为与A类似但不相等 - 则会产生不必要的冲突。我也知道我可以复制定义,但这会破坏类型别名的目的,并涉及许多不必要的代码重复。也许没有解决方案,但我想知道为什么OCaml在这个上如此盲目愚蠢:类型别名应该也意味着构造函数和记录字段别名,不应该吗?
答案 0 :(得分:5)
您可以在引用字段key
时在本地打开模块定义原始类型,如下所示:
module A = struct
type test = Graphics.status
end
module type ASIG = sig
type test = A.test
val atest : test
end
module Func (H : ASIG) = struct
let _ = let open H in atest.Graphics.key
end
或者如果您需要参考几个字段:
let _ = let open H in Graphics.(atest.key, atest.button)
答案 1 :(得分:1)
嗯,这是因为模块签名ASIG
需要为test
的实现查看类型A
的定义。这通常会导致类型可见性出现问题,有时需要重复类型定义,其中合同满足实现而不是引用它。
我们如何修复此警告?在ASIG
中,我们需要像在实现中那样明确地执行type test = A.test
,而不是定义type test = { anint: int }
,所以:
module ASIG = sig
type test = { anint: int }
val atest : test
end
module A = struct
type test = { anint: int }
end
module Func (H : ASIG) = struct
let _ = let open H in atest.anint
end
H
模块无法在其范围内查看anint
,否则,因为签名具有链接到实现的类型(合同)。它也是OCaml哲学的核心概念,它隔离了签名和实现,并根据实现避免了签名。