为什么 OCaml 类型检查中有两条不同的错误消息?

Why two different error messages in OCaml type checking?

从一个完整的表达式开始,ocaml 求值器中的一切都按预期工作。

# fst (fst ((1, 2), 3)) ;;
- : int = 1

想象一下传递函数但未能将它们放在适当上下文中的结果。我将在这些示例中举例说明:

# fst fst ;;  # expect error
Error: This expression has type 'a * 'b -> 'a
       but an expression was expected of type 'c * 'd
# (fst fst) whatever ;;
Error: This expression has type 'a * 'b -> 'a
       but an expression was expected of type 'c * 'd
# fst fst whatever ;;
Error: This expression has type 'a * 'b -> 'a
       but an expression was expected of type ('c -> 'd) * 'e

最后一条错误消息有我不明白的地方。在分析最后一个具有三个标记但没有括号的表达式时,是什么让 ocaml 将类型 ('c -> 'd) * 'e 替换为 'c * 'd

看着 Function application 我只能猜测(但不能说)这可能与关联有关,以及 ocaml 如何看待并列的函数和参数。关于在哪里看的任何提示?

简而言之,您只是走上了统一算法的另一条路,那是 OCaml 类型推断的核心。

括号内的这两种情况和最后一种情况在语义上是等价的,但由于语法中的一些细微差别,a 表示略有不同。 (这是因为语法中有 and 规则,括号,创建一个 ,其实这无所谓)。

由于我们的语法树略有不同,统一在这里选择了两条不同的路径。在第一种情况下,它首先尝试对带括号的简单表达式进行类型检查。在第二种情况下,它尝试推断整体函数类型,然后(粗略地)移动到参数的统一。在任何情况下,类型检查器都会尽快停止。这就是为什么在第一种情况下,typechecker 甚至没有尝试检查括号,因为他已经知道表达式无效。

第二种情况的推理可以这样表达:为了让这个表达式 x y z 进行类型检查,x y 应该评估为可以接受 z 的函数表达式表达式,即 (x y) : 'c -> 'd,其中 'c'd 只是类型变量。由于 x 具有类型 'a * 'b -> 'a,这意味着 'a 必须具有类型 'c -> 'd,替换 'a 我们得到要推断的 y 的类型作为 ('c -> 'd) * 'e。现在,我们查看 y 的实际类型,发现它具有完全不同的类型,无法与推断的类型统一。我们提出错误。