为什么我给这个本地函数添加类型注释时会出错?

Flu*_*lux 4 ocaml types

我定义了一个没有类型注释的函数id

# let id x = x;;
val id : 'a -> 'a = <fun>
# id 123;;
- : int = 123
# id true;;
- : bool = true
Run Code Online (Sandbox Code Playgroud)

一切都按预期进行。

id再次定义,这次使用类型注释:

# let id (x : 'a) : 'a = x;;
val id : 'a -> 'a = <fun>
# id 123;;
- : int = 123
# id true;;
- : bool = true
Run Code Online (Sandbox Code Playgroud)

一切都按预期进行。

然后,我id在没有类型注释的本地表达式中再次定义:

# let id x = x in
  let _ = id 123 in
  id true;;
- : bool = true
Run Code Online (Sandbox Code Playgroud)

一切都按预期进行。

然后,我id在带有类型注释的本地表达式中再次定义:

# let id (x : 'a) : 'a = x in
  let _ = id 123 in
  id true;;
Error: This expression has type bool but an expression was expected of type
         int
Run Code Online (Sandbox Code Playgroud)

惊喜!有错误!

为什么会出现错误?最后一个定义与前三个定义有何不同?我不明白类型注释是如何导致错误的。

And*_*erg 8

首先,需要注意的是,OCaml 的类型变量语义很奇怪,并不符合您的预期。它们被视为统一变量,不一定是多态的。例如,以下内容完全可以,因为'a将简单地与 统一int

# let f (x : 'a) = x + 1;;
val f : int -> int = <fun>
Run Code Online (Sandbox Code Playgroud)

现在,您的示例可能与此类类型变量的隐式作用域规则有关。我认为 Ocaml 将它们的范围限制在周围的模块级声明中。'a这意味着您实际上是在上一个示例中针对某些尚未确定的类型定义单态函数。

您可以通过一个仅调用id一次但'a通过其他方式强制成为特定类型的示例来观察这一点:

# let id (x : 'a) = x in ((5 : 'a); id true);;
Error: This expression has type bool but an expression was expected of type
         int
Run Code Online (Sandbox Code Playgroud)

您甚至无需调用即可获得类似的效果id

# let id (x : 'a) = x in ((5 : 'a); (true : 'a));;
Error: This expression has type bool but an expression was expected of type
         int
Run Code Online (Sandbox Code Playgroud)