为什么编译器在这种情况下停止抱怨`type unit`?

时间:2014-04-16 22:31:27

标签: ocaml

如果我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>

问题

  1. 类型系统推断f是一个以unit为参数并返回'a的函数。但是如果它返回'a,为什么编译器不给Warning 10
  2. 如果编译器没有提供Warning 10,则表示它认为f()返回unit,不是吗?那么为什么它会将'a作为返回类型?

3 个答案:

答案 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类型检查器肯定知道e1e1 ; e2的类型不是unit(它们是'a list)。

对于f1'f2'e1的类型是类型变量'a。它们可能会被unit实例化,具体取决于f1'f2'的使用方式,因此有可能使用它们并且#34;正确&#34;。考虑到这种可能性,编译器不会警告它们。

我个人更喜欢在e1 e1 ; e2中强制unit类型的强制类型。但OCaml在这里更加放松。