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

为什么在OCaml类型检查中有两条不同的错误消息?,ocaml,Ocaml,从完整表达式开始,一切都按照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

从完整表达式开始,一切都按照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


看一下,我只能猜测(但不能说)这可能与关联以及ocaml如何看待并置的函数和参数有关。有没有关于在哪里查找的提示?

简言之,您只是找到了统一算法的另一条路径,它位于OCaml类型推断的核心

括号内的两种情况和最后一种情况在语义上是等价的,但由于语法中的一些微妙之处,a的表示略有不同。(这是因为语法中有和规则,括号创建了一个,但实际上这并不重要)

因为我们有稍微不同的语法树,统一在这里选择了两条不同的路径。在第一种情况下,它首先尝试对括号中的简单表达式进行类型检查。在第二种情况下,它试图推断整个函数类型,然后转向参数的统一(大致)。在任何情况下,typechecker都会尽快停止。这就是为什么在第一种情况下,typechecker甚至没有注意括号,因为他已经知道表达式是无效的


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

谢谢你的关键词和详细的讨论。FWIW,一个关于链接到一些关于这个问题的文章的问题。这个答案不是100%正确
fxy
(fx)y
在语义上并不相同——这两个语法的可选参数表现不同。这就是为什么它们在语法树中有不同的表示。否则,解析器可能会将它们折叠成一个表示形式。@LeoWhite,好的,我同意。但严格来说,我并不是说,一般来说,
fxy
(fx)y
在语义上是相同的。我只是在谈论OP.@ivg提供的例子。当然,我只是觉得这是对答案的有趣补充。如果不是因为可选参数的复杂性,错误消息可能是相同的。