如果我let f1 x = x; x+1
,编译器会抱怨:Warning 10: this expression should have type unit.
如果我let f2 f = f(); 5
,编译器会给val f2 : (unit -> 'a) -> int = <fun>
。
问题
f
是一个以unit
为参数并返回'a
的函数。但是如果它返回'a
,为什么编译器不给Warning 10
?Warning 10
,则表示它认为f()
返回unit
,不是吗?那么为什么它会将'a
作为返回类型?答案 0 :(得分:6)
如果编译器没有给出警告10,则表示它认为f()返回单位,不是吗?
显然,如果编译器给f2
类型(unit -> 'a) -> int
,则表示它认为f
返回'a
。
你在编译器的位置会做什么?
您是否会警告f2
可能会应用于某些返回非单位结果的函数,尽管它实际上可能永远不会被应用?
您是否会f2
类型为(unit -> unit) -> int
并使其不太有用,强制它仅用于返回()
的函数?
您是否会发明一个复杂的推迟警告系统,其中f2
具有类型(unit -> 'a) -> int
,但如果它应用于不返回()
的函数,则会在编译时产生额外警告1}?您是否会使这个系统跨模块工作(函数的推迟警告必须是模块签名的一部分)?
警告只是有用的提示,而不是保证。如果有疑问,不发出警告是通常的解决方案(几乎所有编译器都采用这种解决方案,而不仅仅是OCaml编译器)。
答案 1 :(得分:5)
我认为这是编译器的遗留行为。使用-strict-sequence
进行修复:
$ ocaml
# let f2 f = f(); 5;;
val f2 : (unit -> 'a) -> int = <fun>
可是:
$ ocaml -strict-sequence
# let f2 f = f(); 5;;
val f2 : (unit -> unit) -> int = <fun>
如果您使用ocamlbuild
,则应将其放在_tags
文件中:
true: strict_sequence
答案 2 :(得分:3)
让我在Pascal的回答中加一点。
尝试
let f1' (y : 'a) x = y; x+1
let f1'' (y : 'a list) x = y; x+1
let f2' (f : unit -> 'a) = f(); 5
let f2'' (f : unit -> 'a list) = f(); 5
f1'
和f2'
除了f1''
和f2''
之外没有任何警告。
为什么仅适用于f1''
和f2''
?由于OCaml类型检查器肯定知道e1
中e1 ; e2
的类型不是unit
(它们是'a list
)。
对于f1'
和f2'
,e1
的类型是类型变量'a
。它们可能会被unit
实例化,具体取决于f1'
和f2'
的使用方式,因此有可能使用它们并且#34;正确&#34;。考虑到这种可能性,编译器不会警告它们。
我个人更喜欢在e1
e1 ; e2
中强制unit
类型的强制类型。但OCaml在这里更加放松。