类型推论、类型推断、或隐含类型,是指
编程语言在编译期中能够自动推导出值的
数据类型的能力,它是一些
强静态类型语言的特性。一般而言,函数式编程语言也具有此特性。自动推断类型的能力让很多编程任务变得容易,让程序员可以忽略类型标注的同时仍然允许类型检查。
具有类型推论的语言有:
Rust,
Haskell,
Cayenne,Clean,ML,
OCaml,
Epigram,Scala,
Nemerle,
D,
Chrome,Visual Basic 2008和Boo。计划支持类型推论的有Fortress,
Vala,C# 3.0,
C++11和Perl 6。
在大多数的编程语言中,所有值都有一个
类型,它描述特定值的数据种类。在一些语言中,表达式的类型只在
运行时才知道;这些语言被称作动态类型语言。而另一些语言中,表达式的类型在
编译时就知道,这些语言叫做静态类型语言。在静态类型语言中,函数的输入和输出与
局部变量的类型一般必须用类型标注明确的提供。例如,在
C语言中:
这个函数定义开始处,int addone(int x)声明了addone是函数,接受一个整数类型的参数,并返回一个整数。int result;声明了局部变量result是个整数。在支持类型推论的建议的语言中,代码可写为如下:
这看起来非常像在动态类型语言中写出的代码,但是提供了一些额外的约束(见下)使得能够在编译时推断出所有变量的类型。在上面的例子中,因为+总是接受两个整数并返回一个整数。编译器可以推论出x+1的值是个整数,因此result是个整数,addone的返回值是个整数。类似的,因为+要求它的两个实际参数都是整数,x必须是整数,因此addone接受一个整数实际参数。
但是在随后一行中result2result2可以被隐含的声明为浮点变量,通过隐含的转换表达式中的整数x,简单的因为小数点意外的被放到了整数 1 的后面。这种情况说明了二者之间的区别,“类型推论”不涉及类型转换,而“隐含类型转换”经常没有限制的把数据强制成高精度的数据类型。
类型推论指的是要么部分要么完全自动演绎的能力,把值的类型从表达式的最终计算中推导出来。因为这个过程在编译时间系统性的进行,编译器经常能推出变量的类型或函数的类型标署,而不用给出明确的类型标注。在很多情况下,如果推论系统足够强壮或程序足够简单,有可能完全从程序中省略类型标注。
要获得正确推导出缺乏类型标注的一个表达式的类型所必要的信息,编译器要么随着给它的子表达式(它们自身可以是变量或函数)的类型标注的聚集(aggregate)和后续简约来收集这种信息,要么通过各种原子值的类型的隐含理解(比如 ():
单位; true: 布尔; 42: 整数; 3.14159: 实数; 等等)。通过表达式的最终简约到隐含类型原子值的识别,类型推论语言的编译器有能力编译完全没有类型标注的程序。在高阶编程和
多态性的高度复杂的情况下,编译器不能总是如此推论,偶尔需要类型标注来去除歧义。
这个算法的起源是Haskell B. Curry和Robert Feys在1958年为简单类型lambda演算设计的类型推论算法。在 1969 年Roger Hindley扩展了这项工作并证明他们的算法总能推出最一般的类型。在 1978 年Robin Milner,独立于 Hindley 的工作,提供了等价的算法。在 1985 年Luis Damas最终证明了 Milner 的算法是完备的并扩展它来支持带有多态引用的系统。