这个ocaml片段很好地被顶层打字,这很奇怪。查看结构,如果g的类型为int-> int,如顶层所示,则结构的h x = g x
部分将无法进行类型统一。那么任何人都可以澄清一下吗?
module Mymodule : sig
val h:int ->int
val g: string-> string
end = struct
let g x = x
let h x = g x
end
这是topelevel的回应:
module Mymodule : sig val h : int -> int val g : string -> string end
答案 0 :(得分:8)
我要说string -> string
输入在导出之前不会应用于g
来自模块。在模块内部(因为你没有给它一个类型)它有类型
'a -> 'a
。 (免责声明:我不是模块专家,试图学习。)
答案 1 :(得分:8)
这里要理解的重要一点是,OCaml以组合方式执行类型推断,即它首先会推断struct ... end
的类型,然后它将匹配推断的类型与sig ... end
进行验证该结构确实实现了签名。
例如,如果你写
module Monkey : sig val f : int -> int end =
struct
let f x = x
end
然后OCaml会很高兴,因为它会看到f
具有多态类型'a -> 'a
,它可以专门用于所需类型int -> int
。由于sig ... end
使Monkey
不透明,即签名隐藏了实现,它会告诉您f
具有类型int -> int
,即使实际实现具有多态类型
在您的特定情况下,OCaml首先推断g
的类型为'a -> 'a
,然后h
的类型也为'a -> 'a
。因此它得出结论,该结构具有类型
sig val g : 'a -> 'a val h : 'a -> 'a end
接下来,签名与给定签名匹配。因为'a -> 'a
类型的函数可以专门用于int -> int
以及string -> string
OCaml得出的结论是一切都很好。当然,使用sig ... end
的重点是使结构不透明(实现是隐藏的),这就是为什么顶层不暴露g
的多态类型的原因和h
。
这是另一个显示OCaml如何工作的例子:
module Cow =
struct
let f x = x
let g x = f [x]
let a = f "hi"
end
module Bull : sig
val f : int -> int
val g : 'b * 'c -> ('b * 'c) list
val a : string
end = Cow
回复是
module Cow :
sig
val f : 'a -> 'a
val g : 'a -> 'a list
val a : string
end
module Bull :
sig
val f : int -> int
val g : 'a * 'b -> ('a * 'b) list
val a : string end
end