附录3 编程简史
1940之前
1801,Joseph Marie Jacquard用打孔卡为一台织布机编写指令,在提花织布机(或称甲卡提花织布机,Jacquard loom)上,运用打孔卡上的坑洞来代表缝纫织布机的手臂动作,以便自动化产生装饰的图案。Jacquard织布机是第一台可进行程序控制的织布机。用打孔卡进行编程的概念,直到电子计算机被发明出来之后仍然被广泛运用。
1842,爱达·勒芙蕾丝(Ada lovelace)在1842年至1843年间花费了九个月,将意大利数学家Luigi Menabrea关于查尔斯·巴贝奇新发表机器分析机的回忆录翻译完成。分析机由于其设计思想过于先进,在当时根本没有 被制造出来。(Babbage的分析机一般被认为是现代电子通用计算机的先驱)。她于那篇文章后面附加了一个用分析机计算伯努利数方法的细节,被认为是世界上第一个电脑程序。 “她的努力只遇到了一点点小小的麻烦,那就是:实际上并没有任何计算机能够用来运行她的程序。后来的企业架构师们重新吸收了她的这个技能,用来学习如何更好地使用UML进行编程。”[8]
1890,霍列瑞斯(Herman Hollerith)在观察列车长对乘客票根在特定位置打洞的方式后,意识到他可以把信息编码记载到打孔卡上,随后根据这项发现使用打孔卡来编码并纪录1890年的人口统计数据(这种语言是种编码)。
1936, Alan Turing发明了世间一切程序语言的最终形态,但很快他就被英国军情六处“请”去当007了。与通用图灵机(Universal Turing machine)等价的语言被称为图灵完备的(Turing completeness),它定义了“什么样的语言可以被称作是程序语言”。
1936 , Alonzo Church同时也发明了世间一切程序语言的最终形态,甚至做得更好。他发明的λ演算是当今函数式编程(FP)的鼻祖,对函数式编程有巨大的影响,特别是Lisp 语言。Church是Turing在Princeton的博士生导师,他在λ演算方面的工作先于Turing指出了不存在一个对可判定性问题的通用解法,这后来证明和Turing针对停机问题提出的图灵机模型是等价的。即著名的“Church-Turing”论题。
1940年代
最早被确认的使用电的计算机诞生在1940年代。
程序员在有限的速度及存储器容量限制之下,撰写汇编程序。用汇编语言的这种撰写方式需要花费大量的脑力而且很容易出错。
康拉德·楚泽于1948年发表了他所设计的Plankalkül编程语言的论文。但是在他有生之年却未能将该语言实现。(关于康拉德·楚泽的故事,可参考本书:附录1)
在这段期间被开发出来的重要语言包括有:
1943 - Plankalkül (Konrad Zuse)
1943 - ENIAC coding system
1949 - C-10
1950与1960年代
在这段期间被开发出来的重要语言有:
1951 - Regional Assembly Language
1952 - Autocode
1954 - FORTRAN
1954 - IPL (LISP的先驱)
1955 - FLOW-MATIC (COBOL的先驱)
1957 - COMTRAN (COBOL的先驱)
1958 - LISP
1958 - ALGOL 58
1959 - FACT (COBOL的先驱)
1959 - COBOL
1962 - APL
1962 - Simula
1962 - SNOBOL
1963 - CPL (C的先驱)
1964 - BASIC
1964 - PL/I
1967 - BCPL (C的先驱)
其中有三个现代编程语言于1950年代被设计出来,这三者所派生的语言直到今日仍旧广泛地被采用:
Fortran ,1954
名称取自"FORmula TRANslator"(公式翻译器),约翰·贝克斯(John Backus)针对汇编语言的缺点而研究开发的语言。
LISP,1958
名称取自"LISt Processor"(枚举处理器),约翰·麦卡锡(John McCarthy)在1958年基于λ演算所创造,采用抽象数据列表与递归作符号演算来衍生人工智能。LISP为函数式程序设计语言,所有运算都能以函数作用于参数的方式来实现。LISP核心的操作符只有7个:quote、atom、eq、car、cdr、cons、cond。前三者quote、atom、eq用于符号的推断;car、cdr、cons操纵表格;cond负责分支判断。这种简洁定义,非常接近图灵机原型的纯函数式语言,是现代语言完全无法比拟的。
ALGOL 60,1960
名称取自"ALGOrithmic Language"(算法语言)。ALGOL 60是程序设计语言由技艺转向科学的重要标志,其特点是局部性、动态性、递归性和严谨性,发明于1960年。ALGOL 60强化了当时许多关于计算的想法,并提出了两个语言上的创新功能:
(1)嵌套区块结构(Nested block structure):可以将有意义的代码片段组群成一个区块(block),而非转成分散且特定命名的程序。
(2)词汇范围(lexical scoping):区块可以有区块外部无法通过名称访问,属于区块本身的变量、程序以及函数。
另一个创新则是关于语言的描述方式:
一种名为巴科斯-诺尔范式 (BNF)的数学化精确符号被用于描述语言的语法。之后的编程语言几乎全部都采用类似BNF的方式来描述程序语法中上下文无关的部分。
Pascal、Ada、Simula、C等都借鉴了ALGOL。
COBOL,1961
名称取自"COmmon Business Oriented Language"(通用商业导向语言),由格雷斯·霍波(G.Hopper)所开发。COBOL语言以代码极其冗长和通篇大写字母的书写风格而闻名。据称用COBOL书写的程序超过了2000亿行。另有调查发现世界上目前使用的商业应用软件之中的百分之七十是用COBOL代码编写的。
BASIC,1964
BASIC (初学者通用符号指令代码,Beginners' All-purpose Symbolic Instruction Code),匈牙利人约翰·凯梅尼(John G. Kemeny)与数学教师托马斯·卡茨(Thomas E. Kurtz)认为像FORTRAN那样的语言都是为专业人员设计,没有办法普及。于是,他们在简化FORTRAN的基础上由共同研制出来的。1964年BASIC语言正式发布。第一个BASIC程序在1964年5月1日早上4时,由BASIC编译程序进行编译后成功运行 。1975年,比尔·盖茨把它移植到PC上。
1967-1978:确立基础范式
在1960年代以及1970年代中,结构化程序设计的优点也带来许多的争议,特别是在程序开发的过程中完全不使用GOTO。
在这段期间被开发出来的重要语言有:
1968 - Logo
1970 - Pascal
1970 - Forth
1972 - C语言
1972 - Smalltalk
1972 - Prolog
1973 - ML
1975 - Scheme
1978 - SQL (起先只是一种查询语言,扩充之后也具备了程序结构)
1960年代晚期至1970年代晚期的期间中,编程语言的发展也有了重大的成果。大多数现在所使用的主要语言范式都是在这段期间中发明的。
Simula,1967
第一个面向对象编程语言。由挪威科学家Ole-Johan Dahl和Kristen Nygaard,以Algol 60超集的方式设计开发。
Pascal,1970
Niklaus Wirth(就是那位说:“算法+数据结构=程序” 的人)创造了Pascal,一个过程式的语言。Pascal语言语法严谨,层次分明,程序易写,具有很强的可读性,是第一个结构化的编程语言。Pascal的名称是为了纪念十七世纪法国著名哲学家和数学家Blaise Pascal。
C,1972
源自Ken Thompson发明的B语言,而 B语言则源自BCPL语言。1967年,剑桥大学的Martin Richards对CPL语言进行了简化,于是产生了BCPL(Basic Combined Programming Language)语言。1970年,美国贝尔实验室的 Ken Thompson,以BCPL语言为基础,设计出很简单且很接近硬件的B语言(取BCPL的首字母)。并且他用B语言写了第一个UNIX操作系统。
1971年,Dennis M.Ritchie伙同Thompson一起,合作开发UNIX。1972年, D.M.Ritchie 在B语言的基础上设计出C语言。Thompson和Ritchie就用C完全重写了UNIX。在开发中,他们还考虑把UNIX移植到其他类型的计算机上使用。C语言强大的移植性(Portability)在此显现。机器语言和汇编语言都不具有移植性,为x86开发的程序,不能在Alpha,SPARC和ARM等机器上运行。而C语言程序则可以使用在任意架构的处理器上,只要那种架构的处理器具有对应的C语言编译器和库,然后将C源代码编译、连接成目标二进制文件之后即可运行。
未来的JVM的“虚拟机”的思想,在某种程度上正是源自这里,通过对不同平台上JVM的实现,向上封装一层,从而使得基于JVM的编程语言可以更大限度的实现了跨平台(当然,对应需要实现各个平台上(比如说Windows,Linux,Mac OS)的JDK)。
Smalltalk,1975
由Alan Kay,Dan Ingalls,Ted Kaehler,Adele Goldberg等于70年代初在Xerox PARC开发的面向对象编程语言。
Alan Kay 总结了 Smalltalk 的五大基本特征。这是第一种成功的面向对象程序设计语言,也是Java 的基础 语言。通过这些特征,我们可理解“纯粹”的面向对象程序设计方法是什么样的:
(1) 所有东西都是对象。可将对象想象成一种新型变量;它保存着数据,但可要求它对自身进行操作。理论 上讲,可从要解决的问题身上提出所有概念性的组件,然后在程序中将其表达为一个对象。
(2) 程序是一大堆对象的组合;通过消息传递,各对象知道自己该做些什么。为了向对象发出请求,需向那 27
个对象“发送一条消息”。更具体地讲,可将消息想象为一个调用请求,它调用的是从属于目标对象的一个 子例程或函数。
(3) 每个对象都有自己的存储空间,可容纳其他对象。或者说,通过封装现有对象,可制作出新型对象。所 以,尽管对象的概念非常简单,但在程序中却可达到任意高的复杂程度。
(4) 每个对象都有一种类型。根据语法,每个对象都是某个“类”的一个“实例”。其中,“类”(Class) 是“类型”(Type)的同义词。一个类最重要的特征就是“能将什么消息发给它?”。
(5) 同一类所有对象都能接收相同的消息。[10]
Smalltalk对其它众多的程序设计语言的产生起到了极大的推动作用,例如:Objective-C,Actor, Java 和Ruby等。90年代的许多软件开发思想得利于Smalltalk,例如Design Patterns, Extreme Programming(XP)和Refactoring等。
Prolog,1972
Prolog语言最早由Aix-Marseille大学的Alain Colmerauer与Phillipe Roussel、Kowalski等人于60年代末研究开发。它建立在逻辑学的理论基础之上, 最初被运用于自然语言等研究领域。现已广泛的应用在人工智能的研究中,可以用来建造专家系统、自然语言理解、智能知识库等。
ML,1973
ML(Meta Language)是Robin Milner主管LCF项目时(1970),作为LCF项目的元语言(Meta Language)而设计的,这也是其名字的来历。LCF项目是受Dana Scott给出的一组逻辑原则启发而设立的,致力于开发一种“可计算函数逻辑”(Logic of Computable Functions)。目标是构造一个方便实用的系统,来自动的或者半自动的证明函数程序中一些有趣的性质。今天,大多数著名的推理系统都是用ML写的。目前ML有两个发展分支:Standard ML和Caml。
ML使用了Hindley-Milner类型推论算法来推测大多数值的类型,而不需要四处使用注解。ML一般被归为非纯函数式编程语言,因为它允许副作用和指令式编程。这一点和纯函数式编程语言例如Haskell很不一样。ML特性有惰性求值的求值策略,一阶类型函数, 带有垃圾收集的自动内存管理, 参数多态,静态数据类型,类型推断,代数数据类型,模式匹配和异常处理等。ML中的思想影响了众多的语言,例如Haskell,Cyclone和Nemerle。
这些语言都各自演展出自己的家族分支,现今多数现代编程语言的祖先都可以追溯他们其中至少一个以上。
1980年代:增强、模块、性能
1980年代的编程语言与之前相较显得更为强大。C++合并了面向对象以及系统程序设计。美国政府标准化一种名为Ada的系统编程语言并提供给国防承包商使用。日本以及其他地方运用了大量的资金对采用逻辑编程语言结构的第五代语言进行研究。函数编程语言社区则把焦点转移到标准化ML及Lisp身上。这些活动都不是在开发新的范式,而是在将上个世代发明的构想进一步发扬光大。
然而,在语言设计上有个重大的新趋势,就是研究运用模块或大型组织化的程序单元来进行大型系统的开发。Modula、Ada,以及ML都在1980年代发展出值得注意的模块化系统。模块化系统常拘泥于采用泛型程序设计结构:泛型存在(generics being)、本质(essence),参数化模块(parameterized modules)。(参阅多态)
尽管没有出现新的主要编程语言范式,许多研究人员仍就扩充之前语言的构想并将它们运用到新的内容上。举例来说,Argus以及Emerald系统的语言配合面向对象语言运用到分布式系统上。
1980年代的编程语言实现情况也有所进展。计算机系统结构中RISC的进展假定硬件应当为编译器设计,而非身为人类的汇编语言程序员。借由中央处理器速度增快的帮助,编译技术也越来越积极,RISC的进展对高级语言编译技术带来不小的关注。
语言技术持续这些发展并迈入了1990年代。
在这段期间被开发出来的重要语言包括有:
1980 - Ada
1983 - C++ (加上类的C)
1984 - Common Lisp
1985 - Eiffel
1986 - Erlang
1987 - Perl
1988 - Tcl
1989 - FL (Backus)
C++,1983
Bjarne Stroustrup,他使用过Simula和ALGOL,接触过C。他对Simula的类体系感受颇深,对ALGOL的结构也很有研究,深知运行效率的意义。既要编程简单、正确可靠,又要运行高效、可移植。于是Bjarne Stroustrup以C为背景,以Simula思想为基础,把他所听说过的一切都试图嫁接到C上,创造出了C++。它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。C++擅长面向对象程序设计的同时,还可以进行基于过程的程序设计,因而C++就适应的问题规模而论,大小由之。
1990年代:互联网时代
1990年代未见到有什么重大的创新,大多都是以前构想的重组或变化。这段期间主要在推动的哲学是提升程序员的生产力。
许多"快速应用程序开发" (RAD) 语言也应运而生,这些语言大多都有相应的集成开发环境、垃圾回收等机制,且大多是先前语言的派生语言。这类型的语言也大多是面向对象的编程语言,包含有Object Pascal、Visual Basic,以及C#。
Java,1995
1995年,互联网的蓬勃发展给了Oak(Java之前的名字)机会。Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。
我们将在下一章中介绍Java编程简史。另外,关于上面提到的“提升程序员的生产力”的哲学理念,本书介绍的SpringBoot框架,就是为了推动程序员的生产力而设计开发的。不管在编程语言设计领域,还是在编程框架的开发领域,很大一部分的目的,就是为了这一点。
在这段期间被开发出来的重要语言包括有:
1990 - Haskell
1991 - Python
1991 - Visual Basic
1993 - Ruby
1993 - Lua
1994 - CLOS (part of ANSI Common Lisp)
1995 - Java
1995 - Delphi (Object Pascal)
1995 - JavaScript
1995 - PHP
1997 - REBOL
1999 - D
当今的趋势
编程语言持续在学术及企业两个层面中发展进化,目前的一些趋势包含有:
在语言中增加安全性与可靠性验证机制:额外的堆栈检查、信息流(information flow)控制,以及静态线程安全。
提供模块化的替代机制:混入(mixin)、委派(delegates),以及观点导向。
组件导向(component-oriented)软件开发。
元编程、反射或是访问抽象语法树(Abstract syntax tree)
更重视分布式及移动式的应用。
与数据库的集成,包含XML及关系数据库。
支持使用Unicode编写程序,所以源代码不会受到ASCII字符集的限制,而可以使用像是非拉丁语系的脚本或延伸标点符号。
图形用户界面所使用的XML(XUL、XAML)。
等等。
在这段期间被开发出来的重要语言包括有:
2001 - C#
2001 - Visual Basic .NET
2002 - F#
2003 - Scala
2003 - Factor
2006 - Windows PowerShell
2007 - Clojure
2009 - Go
2014 - Swift (编程语言)
编程语言发展史上的杰出人物
约翰·冯·诺伊曼,操作系统概念的发起者。
肯·汤普逊,发明了Unix。
丹尼斯·里奇,发明了C。
约翰·巴科斯,发明了Fortran。
阿兰·库珀,开发了Visual Basic。
詹姆斯·高斯林,开发了Oak,该语言为Java的先驱。
安德斯·海尔斯伯格,开发了Turbo Pascal、Delphi,以及C#。
葛丽丝·霍普,开发了Flow-Matic,该语言对COBOL造成了影响。
肯尼斯·艾佛森,开发了APL,并与Roger Hui合作开发了J。
比尔·乔伊,发明了vi,BSD Unix的前期作者,以及SunOS的发起人,该操作系统后来改名为Solaris。
艾伦·凯,开创了面向对象编程语言,以及Smalltalk的发起人。
Brian Kernighan,与丹尼斯·里奇合著第一本C程序设计语言的书籍,同时也是AWK与AMPL程序设计语言的共同作者。
约翰·麦卡锡,发明了LISP。
比雅尼·斯特劳斯特鲁普,开发了C++。
尼克劳斯·维尔特,发明了Pascal与Modula。
拉里·沃尔,创造了Perl与Perl 6。
吉多·范罗苏姆,创造了Python。
......
名词纪要
二进制
二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”,由莱布尼兹发现(启蒙思想源自中国古代的易经八卦)。
指令
告诉计算机从事某一特殊运算的代码。如:数据传送指令、算术运算指令、位运算指令、程序流程控制指令、串操作指令、处理器控制指令。
代码化指令序列就是计算机程序。
汇编
汇编是离机器码最近的一个人类可阅读可编写的语言形式。计算机CPU只能处理010101这样的二进制码。人类最早用0 和 1(纸袋打孔等) 来写程序,这样搞起来太费劲,效率太低。
幸亏人类有着聪明的善于思考,抽象问题的大脑。所以后来就有了汇编语言。人类用汇编语言来写人类看得懂的程序(mov, add ... )。 但是这样的汇编指令,CPU又看不懂了。怎么办?我们聪明的人类设计了“编译器”。 之后这个程序会把人类编写的程序,翻译成CPU能理解的010101.........通过编程语言建立起人类和CPU之间的翻译工作。(一切皆是映射)
编译器
简单讲,编译器就是将“一种语言(通常为高级语言)”翻译为“另一种语言(通常为低级语言)”的程序。(一切皆是映射)是连接高级语言(如Pascal、C、C++、汇编语言)与机器语言(Machine code,01)的桥梁。
对于Java、C#等高级语言而言,编译器先把源码(SourceCode)编译成通用中间语言的字节码(ByteCode)(遵循一套各自平台上定义的协议规范)。最后运行的时候通过通用语言运行库,转换成最终可以被CPU直接执行的机器码。
参考资料
1 https://www.zhihu.com/question/22193700
2 http://baike.baidu.com/item/%E4%BA%8C%E8%BF%9B%E5%88%B6
3 http://baike.baidu.com/item/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%AF%AD%E8%A8%80
4 http://baike.baidu.com/item/LISP/22083
5 http://baike.baidu.com/item/pascal/241171
6 http://baike.baidu.com/item/ada/5606819#3
7 https://en.wikipedia.org/wiki/History_of_programming_languages
8 http://james-iry.blogspot.co.at/2009/05/brief-incomplete-and-mostly-wrong.html
9 http://baike.baidu.com/item/%CE%BB%E6%BC%94%E7%AE%97
10 《Java编程思想》(Bruce Eckel)