为什么这个 OCaml 定义接受了错误的类型?

Why is this OCaml definition accepted with a wrong type?

我定义了一个错误函数:

let first : 'a -> 'b -> 'a = fun x y -> y ;;
(* Result: val first : 'a -> 'a -> 'a = <fun> *)

编译器接受它并将类型从 'a->'b->'a 更改为 'a->'a->'a。 它不应该工作,因为 return 类型应该是 'a,而不是 'b。 正确实施:

let first : 'a -> 'b -> 'a = fun x y -> x ;;
(* Result: val first : 'a -> 'b -> 'a = <fun> *)

它为什么起作用以及如何防止编译器像这样更改类型?它成为更复杂的表达式的问题。

默认情况下,OCaml 中显式注释中的类型变量是统一变量。特别是,它们可用于添加一些等式约束。例如,xy 共享的 'a 注释允许编译器检测到

let rec eq (x:'a) (y:'a) = match x, y with
| `Leaf _, `Node _ -> false 
| `Node n1,`Node n2 ->
  eq n1#left n2#left && eq n1#right n2#right 

案例

| _, `Leaf -> ...

缺失,但如果不将类型变量 'a 细化为相当复杂的类型 x,那将无法工作。

问题是注释不是您想要的。如果你想强制一个函数具有多态类型'a -> 'b -> 'a,你可以使用显式通用量化:

let wrong: type a b. a -> b -> a = fun x y -> y

使用此注释,类型检查失败并出现错误:

Error: This expression has type b but an expression was expected of type a

符合预期。而正确的函数

let ok: type a b. a -> b -> a = fun x y -> x

编译没有问题。

在这里,前缀 type a b. 读作“对于所有可能的类型 ab”,此注释强制 f 的类型等于 'a -> 'b -> 'a 没有对类型变量 'a'b.

进行任何细化(也称为统一)