编程语言中的类型声明来自哪里?

时间:2014-09-27 06:17:30

标签: types programming-languages

当我们在C / C ++中定义一个函数时,我们输入类似

的东西
int add(int a, int b){
    return a+b;
}

然而,我们在函数中实际做的是获得两个可求和的东西的总和并返回它的值。在许多早期创建的编程语言中,如Algol,C,pascal,您应该在对其执行某些操作之前声明变量的类型。此外,这在许多主流语言中都是必需的,例如Java,C#(尽管它有像“var”这样的关键字)。

在Python等许多动态编程语言中,我们将以前的函数重写为:

def add(a,b):
    return a+b

没有函数和参数的“类型标识符”。我在想的是,与C / C ++这样的语言相比,Python版本似乎更接近程序员心中的原始想法:只是封装了将两个数字加在一起并返回总和的行为。

另一方面,在实践中,这些类型声明对减少错误有很大帮助,例如,如果我只需要两个数字的总和,我就不会将字符串传递给“add”函数。如果我传递两个字符串,编译器会将此视为错误。类型声明似乎是本例中代码的保护。

但令我困惑的是,为什么这么多早期创建的语言需要变量的类型声明?为什么大多数带有类型声明的语言都比较早,而且大多数语言版本更简单的语言都会出现在历史的后面?

我知道我们无法判断哪种方法“更好”并且它们都是图灵完备的,但我只是好奇为什么早期的语言创建者没有选择更直观和更简单的语法,而是专注于实现功能100%,但选择添加类型标识符作为语言的需要部分(问题1)?此外,在早期,人们对代码应该是什么样子有非常模糊的印象,所以我想类型标识符的想法必须来自某个地方。我的第二个问题是类型声明的概念来自哪里(数学?练习?还是其他地方?)?如果我知道答案,我想我会更好地理解“类型”。

2 个答案:

答案 0 :(得分:4)

可以说,数据类型的概念存在于编程语言中。第一种使用机器语言的语言,甚至是那些与你相关的语言,比如添加整数或添加浮点数。但是,通过使用不同的指令来进行类型区分。

第一个更高级别的语言是Fortran(20世纪50年代中期)。 Fortran区分了变量类型,但它不是基于类型声明来实现的,而是基于变量名称来实现的。例如,变量i,j k等将是整数,而p,q,r浮动(IIRC)。这允许使用相同的方便的符号来例如另外,不管是什么类型。

显然,这是一个非常黑客的想法,并没有扩展到任何更有趣的类型系统。因此,下一代语言,尤其是Algol(20世纪50年代后期),使其更加明确,并为类型引入了语法。

随着语言变得更高级并支持更有趣的数据类型,类型系统也变得更加有趣。在某些时候(大约1970年),人们意识到编程语言中的类型实际上与数学中已知类型的概念密切相关:即,在20世纪30年代发明的类型化的lambda演算中。实际上,人们意识到计算逻辑和编程语言之间的关系实际上是一个非常接近的关系,并且编程语言可以解释为lambda calculi的变体,这是大多数现代编程语言理论(和设计)确实

Untyped(或所谓的“动态类型”,明显滥用术语)编程语言也很老。第一个是Lisp(20世纪50年代后期),实际上已经从无类型的lambda演算中获得灵感。然而,这种语言直到很久以后才开始流行。原因是它们在运行时系统中需要更昂贵的机器,这在早期的计算中是不可承受的,并且通常仍然不是今天。 (最近关于这些语言的炒作似乎有点消失了,因为它(重新)发现这种形式的发展不能很好地扩展 - 所有现在为这些语言发明的类型系统都见证了这种情况:Typed Scheme,TypeScript,MyPy,Hack等。)

编程语言部分从逻辑btw中获取的另一个灵感是类型推断。即使最初发明的类型化的lambda calculi,也有两种形式:显式类型和隐式类型。功能语言ML是第一个采用类似的编程思想(20世纪70年代后期):ML程序是完全类型检查而不编写单一类型声明。最近,这种想法已经达到主流语言,但通常采用的方式更为有限。

这是要指出typed和untyped之间的区别不一定与语法和类型声明的存在有关 - 一种语言可以(“静态地”)键入并且不需要类型声明。

答案 1 :(得分:1)

安德烈亚斯'优秀的历史并没有解决问题的第一部分。数据类型从早期就存在于编程语言中,但问的问题是为什么需要类型声明。

原因是内存容量。包括编译器在内的程序当时必须运行非常有限的内存。这有两个直接后果:

  • 程序员无法使用一刀切的方法来表示数据,因为它使用内存效率低下;他们希望专门针对不同类型的数据表示,以便一次可以将更多数据放入内存中。

  • 编译器无法同时将整个程序放在内存中,因此他们需要能够单独编译部分程序,并在以后链接它们。要编译一个部分,通常需要知道数据在其他部分中的表示方式。

至少在C中的类型声明为这两个问题提供了解决方案。