我一直在考虑类型推断如何在以下OCaml程序中起作用:
let rec f x = (g x) + 5
and g x = f (x + 5);;
当然,程序很无用(永远循环),但类型呢? OCaml说:
val f : int -> int = <fun>
val g : int -> int = <fun>
这完全是我的直觉,但类型推断算法如何知道这一点?
假设算法首先考虑“f”:它可以得到的唯一约束是“g”的返回类型必须是“int”,因此它自己的返回类型也是“int”。但它不能通过“f”的定义来推断其论证的类型。
另一方面,如果它首先考虑“g”,它可以看到它自己的参数的类型必须是“int”。但是之前没有考虑过“f”,就不能知道“g”的返回类型也是“int”。
它背后的魔力是什么?
答案 0 :(得分:8)
假设算法首先考虑“f”:它可以得到的唯一约束是“g”的返回类型必须是“int”,因此它自己的返回类型也是“int”。但它不能通过“f”的定义来推断其论证的类型。
它无法将其推断为具体类型,但它可以推断出某些东西。即:f
的参数类型必须与g
的参数类型相同。因此,基本上在查看f
之后,ocaml知道以下类型:
for some (to be determined) 'a:
f: 'a -> int
g: 'a -> int
查看g
后,它知道'a
必须是int
。
要更深入地了解类型推断算法的工作原理,您可以阅读有关Hindley-Milner type inference或this blog post的维基百科文章,该文章似乎比维基百科文章更友好。
答案 1 :(得分:8)
这是我发生的事情的心理模型,可能与现实相匹配,也可能不符合现实。
let rec f x =
好的,此时我们知道f
是一个带参数x
的函数。因此我们有:
f: 'a -> 'b
x: 'a
某些'a
和'b
的。下一个:
(g x)
好的,现在我们知道g
是一个可以应用于x
的函数,所以我们添加
g: 'a -> 'c
到我们的信息列表。继续...
(g x) + 5
啊哈,g
的返回类型必须是int
,所以现在我们已经解决了'c=int
。此时我们有:
f: 'a -> 'b
x: 'a
g: 'a -> int
继续......
and g x =
好的,这里有一个不同的x
,让我们假设原始代码改为y
,以使事情更加明显。也就是说,让我们将代码重写为
and g y = f (y + 5);;
好的,我们在
and g y =
现在我们的信息是:
f: 'a -> 'b
x: 'a
g: 'a -> int
y: 'a
因为y
是g
的参数......我们继续前进:
f (y + 5);;
这告诉我们y+5
y
有int
类型,它解决了'a=int
。由于这是g
的返回值,我们已经知道它必须是int
,这解决了'b=int
。如果代码是
and g y =
let t = y + 5 in
let r = f t in
f r;;
然后第一行显示y
是int
,因此求解'a
,然后下一行会说r
的类型为'b
},然后最后一行是g
的返回,它解决了'b=int
。