从完整表达式开始,一切都在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
最后一条错误讯息有我不明白的地方。在分析具有三个令牌但没有括号的最后一个表达式时,('c -> 'd) * 'e
的ocaml替换类型'c * 'd
是什么?
看Function application我只能猜测(但不能说)这可能与关联有关,以及ocaml如何看待函数和参数并列。关于在哪里看的任何提示?
答案 0 :(得分:3)
简而言之,您只是触及统一算法的不同路径,这是OCaml类型推断的核心。
两种情况,括号和最后一种在语义上是等价的,但由于语法中的某些微妙性,表示略有不同。 (这是因为语法和括号中有规则和括号创建了一个,但实际上这并不重要。)
由于我们的语法树略有不同,统一在这里选择了两条不同的路径。在第一种情况下,它首先尝试使用带括号的简单表达式进行类型检查。在第二种情况下,它试图推断整体函数类型,然后转移到参数的统一(粗略)。在任何情况下,类型检查员都会尽快停止。这就是为什么在第一个案例中,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
的实际类型,并看到它具有完全不同的类型,无法与推断的类型统一。我们提出错误。