在计算机「平民化」的进程中,有些语言已经被掩埋了,但依然有人怀揣满满的好奇心去揭开这段历史。本文作者 Sean Haas 便是其中之一。
选自VICE,作者:Sean Haas,机器之心编译,机器之心编辑部
BASIC 语言在计算机程序设计领域占有重要地位,它流行于上世纪七八十年代,带领整整一代人进入计算领域。BASIC 广受欢迎的原因非常简单:它面向的不是程序员,而是计算机入门者。这种语言与早期家庭计算的平等主义世界观非常契合:如果你会打字,你就可以用计算机;如果你会用计算机,你就可以编程。
当然,BASIC 也不是哪个人拍脑袋想出来的。和其他语言一样,它也有完整的谱系和根源。BASIC 的后代很好找,比如 Visual BASIC,但它的「先驱」就没有那么广为人知了。
这个「先驱」名叫「达特茅斯超简化编程实验(Dartmouth Oversimplified Programming Experiment)」,简称 DOPE。它是一门奇怪的语言,但确实显示出了 BASIC 语言开始形成时的骨架。
DOPE:BASIC 的先驱
计算的历史很容易用问题来概括。在 IBM,严重的问题被称为「恶龙」,这令人联想到:程序员就是被派去斩*恶龙的。在计算机发展的早期,「可及性(accessibility)」就是那头最大的恶龙。也就是说,如何让更多人用上计算机是当时最令人头疼的问题。早期的计算机本身就是庞然大物,而且又贵又难用。那时候,大多数程序员自己都不碰计算机,而是将一堆一堆的穿孔卡片交给技术人员,让他们小心翼翼地输入保护良好的机器。
那个时期,计算机是一件新奇的事物,但要让它真正发挥作用,还得靠人,而且用计算机的人越多越好。50 年代后期,计算机实现了稳步发展,但可及性成为发展瓶颈。
此时,编程语言应运而生,FORTRAN、ALGOL 等「上古」语言都起源于这一时期。开发 FORTRAN 的目的在于让非计算机领域的科学家更加容易利用计算机进行计算。此处的关键词是「科学家」。如果你遵循 FORTRAN 的逻辑,那么计算机就是研究工具,是是你藏在实验室里的东西。虽然这是一项重要的应用,但作用有限。毕竟从整体来看,并没有多少人是科学家。
接下来就轮到两位「屠龙者」——John Kemeny 和 Thomas Kurtz 登场了。Kemeny 长期担任达特茅斯学院数学系主任,Kurtz 是他的同事。
二战期间,Kemeny 作为数学家参与了曼哈顿计划(美国陆军部研制原子弹计划),直接与冯 · 诺依曼合作。Kemeny 花了一年的时间来分析和计算数字。1945 年初,他用笨重的 IBM 制表机完成了自己的工作。那年年底,第一批电子数字计算机投入使用,Kemeny 亲眼目睹了它们对曼哈顿计划的影响。第二年,Kemeny 写了他的第一个程序。
Thomas Kurtz 的出场时间稍晚一点。1951 年,Kurtz 参加了加州大学洛杉矶分校的暑期课程。在那里,他第一次看到了一台运行中的计算机。当时,他已经在普林斯顿大学的数学专业读研究生了。这个小小的插曲激发了他对计算机的兴趣。在学会编程之后,计算就成了他职业生涯不可分割的一部分。
Kemeny 和 Kurtz 都见证了计算机如何改变自己的生活,也认识到这项技术不会止步于此。
随后,两人给自己设置了一项任务:教达特茅斯学院的每一位学生使用计算机。在此之前,该学院理工科的学生已经接触过计算机,但这部分学生人数有限。
真正的问题在于,怎么教?一个学心理的学生为什么要学这些?当然,计算机将会改变一切。这种话在课堂上说一说没问题,但你要怎么向学生介绍这种机器?
这个问题的最终解是 BASIC。与早期的其他语言不同,BASIC 是专为「科学家」、「程序员」以外的人设计的。在这门语言中,不必要的结构被删除,数据被简化,语法被简化至最低限度。最后,BASIC 被打造成一门非常容易学习的大众语言。
与同时期的其他语言相比,BASIC 极其简单。以 FORTRAN 为例,在 FORTRAN 中,变量需要用特定的数据类型来声明,而且变量声明需要在程序的特定位置进行。相比之下,BASIC 不使用显式类型,任何变量都可以保存任何你想要的东西。你甚至不需要声明变量,只需要说「LET A = 1」就可以了。甚至 BASIC 的语法也是一股清流。这门语言只用字母、数字和一些数学运算符,连行尾、括号都可以不用。
为了简单,BASIC 放弃了更强大的功能。对象、抽象,甚至前面提到的变量类型都没有了。BASIC 只满足基本需求。
在校园里,BASIC 很受欢迎。老师们将这种语言融入课堂,学生们也乐意接受。在这之后,BASIC 自然而然地进入家用电脑,成为数百万人进入数字世界的入门工具。
Kemeny 和 Kurtz 合著的《Back to BASIC》是关于 BASIC 语言最权威的一本著作。也是在这本书中,我第一次听说了 DOPE。
50 年代末 60 年代初,Kemeny 和 Kurtz 开始探索如何让学生接触计算机,具体来说即为一点基础都没有的学生寻找一种编程语言。由于现有的语言无法满足要求,他们就自己创造了一门语言。
当时,达特茅斯数学系配置了一台 LGP-30 计算机,这是一种相对便宜且功能一般的机器,有 30 千字节的 RAM 可以使用。在之后的数年里,这台机器经历了一些奇怪的实验,DOPE 便是其中之一,但书中并没有太多的细节描述。在这本书开头的某个章节中,Kemeny 写道:
「我有一个还在上高中的学生,名叫 Sidney Marshall。他在达特茅斯上微积分课。我让他用一种名为 DOPE 的语言在 LGP-30 上做实验。DOPE 太原始了,没多大用,但它是 BASIC 的先驱(precursor)。」
当时,DOPE 被用在达特茅斯数学系的计算机上,Kemeny 负责监督它的产出。作为一名程序员,我一直以为 BASIC 是一门独立的语言,和其他任何语言都没有多大关系。但现在看来,这是我的一个知识盲区,而且陷入这一盲区的不止我一个。
运行 DOPE
关于 DOPE,可以查到的信息并不多,但我还是在 Thomas Kurts 写的《History of Programming Languages》里看到了一小块代码。那是用 DOPE 写的,虽然不足以帮助我们理解这门语言,但却可以证明它的存在。之后,我通过查找一些访谈和引文构建起了这门语言的概况。DOPE 创建于 1962 年,只在一门数学课上使用过一个学期。这是向无障碍编程迈出的一步,但还不够大。
凭借这些线索,我找到了一个藏在达特茅斯学院档案馆里的文件夹,里面的手稿被简单地命名为「达特茅斯超简化编程实验」,存在 Kurtz 的笔记文件夹里。这篇论文写于 1962 年,提出了一种完全不同的编程方法。当然,这里指的不是 BASIC,但已经很接近了。
首先,这份关于 DOPE 的手稿回答了我最大的困惑:为什么关于这门语言的信息那么少?从这门语言的名称中,我们能略知一二:DOPE 只是一项实验,用来验证 Kemeny 和 Kurtz 的想法。而且,描述 DOPE 的这篇论文从来没有发表过,部分原因在于:它不是一门正式的语言,只是一份教案,而学生就是小白鼠。
对我来说,下一步就非常明确了。这篇论文介绍了关于 DOPE 的所有细节、示例问题、逻辑图表以及特性。但我想理解这门语言,上手使用无疑是最好的方式。在使用过程中,无法运行现有的 DOPE 代码是我遇到的一大问题。显然, GNU binutils 不支持这门语言。我也找不到任何用于原始实现的代码。为了让这门语言重见天日,我着手构建了一个解释器(一个能理解和执行源代码的程序)。
自己动手实现 DOPE 不但有助于深入理解这门语言,还让我弄懂了为什么它最终没被采用。
复活一门死去的语言听起来似乎很困难,但其实也没那么难。甚至在运行解释器之前,我就已经开始看到 DOPE 和 BASIC 之间的联系了。BASIC 之所以如此受欢迎,易于实现是很重要的一点。它是被设计成这样的。该语言的结构决定了,它的编译非常简单。达特茅斯的 BASIC 遵循非常严格的语法结构,每一行都以一个数字开始,然后是一个操作,再然后是参数。很简单,很容易用计算机分析,也很容易上手。
DOPE 的每一行以一个行号开始,然后是一个操作,再然后是参数,BASIC 的结构就继承于此。对于实现这门语言的人来说,这一点帮助我节省了大量的时间和代码。你只需要将每一行分成若干 token,操作总是在同一个位置,参数紧随其后,没有任何歧义或变动幅度。
根据 Kemeny 的论文,DOPE 编译器可以在一分钟内将代码转换为可执行文件。在今天看来,这个速度太慢了,但对于当年的 LGP-30 来说,这个速度已经很不错了。后来,这种简化的语法结构使得 Kemeny 和 Kurtz 可以在他们的 BASIC 实现中使用一些技巧。达特茅斯的 BASIC 是编译的,但呈现给用户的是一个可交互环境。在后端,BASIC 代码以最小的延迟进行编译,但对于学生来说,学校的计算机似乎可以「说」流利的 BASIC 语言。
BASIC 稍微偏离了严格的格式。你可以用 BASIC 写出数学表达式,所以「LET A = 1 1」是有效的。本质上,数学表达式可以被视为参数,但对于用户来讲,你可以用 BASIC 编写数学表达式,就像你草草记下一个方程一样。
但 DOPE 并非如此。由于硬件所限,它被打造成一门更加简洁的语言。举个例子,还是上面的 BASIC 语句,即 1 1,DOPE 出来的结果是「 '1'1'A」。这个形式没那么好看,是不是?具体来说,DOPE 看起来更像是汇编语言,大多数运算符都是单个字符,每一行只能执行一个简单的运算,参数列表都是固定长度,所有常见的数学、赋值、循环和打印操作都以统一的形式呈现。
此外,受到硬件的限制,DOPE 不会用空格进行分隔,LGP-30 计算机上运行的其他语言也是如此。幸运的是,在 BASIC 被开发出来的时候,达特茅斯已经有了更好的硬件,因此也就摆脱了前辈们的命运。
除了这些表面的问题,DOPE 还有更深层次的缺陷。
变量是所有编程语言的基本要素,是存储和操作数据的载体,也是 DOPE 与 BASIC 一脉相承的另一个体现。DOPE 有一种非常特殊的类型系统。它几乎是隐式的,但只是轻微地。
DOPE 的每个变量是一个浮点数,还有四个特殊的变量:E、F、G、H。这是包含 16 个元素的数组,最多可以容纳 16 个数字。在你用 DOPE 时,你只需要记住这四个变量是不同的。
DOPE 也没有字符串,你不能存储或操作词或字母。几乎所有编程语言都能够以某种方式处理字符串,因此这个局限还是非常明显的。但鉴于 DOPE 只用于处理数学工作,缺少字符串也不是什么大问题。
这里有一点微妙之处。所有的变量都存储为浮点,因此你输入的任何一个数字都会被转换。将变量设置为 1,DOPE 将其转换为 1.000。在你打印变量时,DOPE 会找出最合理的格式并展示。因此,如果这个浮点数没有小数位,它就不会显示小数点。对于严谨的程序员来说,这听起来就像一场噩梦。由于没有数据类型,DOPE 将对数据类型的控制给剥夺了。程序员不喜欢放弃控制,在 DOPE 那个年代尤其如此。
当然,DOPE 并不是为程序员设计的,而是为那些分不清整数 1 和浮点 1 区别的学生而设计的。DOPE 中奇怪的类型系统意味着你可以在不教数据类型的情况下教授编程,也不用解释 1.0 和 1 的区别。对于外行来说,这些规则没有多大意义,所以不要也罢。你所得到的是一本温和的计算机入门指南。
对于 BASIC 用户来说,这点可能有点令人吃惊,但该语言的早期版本确实也有一个非常类似的类型系统。在达特茅斯 BASIC 语言的第一个版本中,每个变量都被存储为一个浮点,为输入和输出提供智能格式。后续的版本中出现了字符串,但这里的字符串是以数组的形式出现的。在 BASIC 中,数组要用 DIM 操作来声明。它告诉计算机为新的数组腾出空间,并赋予该数组一个新名字。在早期版本中,计算机需要将一个变量转换为一个含有 10 个元素的数字数组。这是 BASIC 与 DOPE 分道扬镳的领域之一,我认为这是一件好事。
DOPE 保留了四个变量作为数组。这点运行良好,但稍显笨拙。要记住哪些字母是列表,哪些是数字还是很烦人的。它增加了一层不合逻辑的复杂性。Kemeny 和 Kurtz 放弃这点是正确的。
最后要提的一点是 DOPE 的行号,这也是 BASIC 的特色之一。任何了解或者看过 BASIC 代码的人对这个语法应该都不会陌生。每一行都有一个数字,它同时作为标签和一种编辑程序的方式。通过显式地定义行号,程序员可以为代码的每个部分命名。DOPE 也用行号,但更加有限,每一行都有一个隐式的数字,从 1 开始,直到 99。
你无法控制 DOPE 的行号,但每个号码都有自己的标签。这些行号使得 DOPE 成为一门成熟的编程语言。饱受诟病的 GOTO 语句存在于这一早期语言中,只是用了另一个名字。GOTO 告诉 BASIC 将执行跳转到特定的行号。这是一种处理程序流控制的简单方法,但通常还有更好的选择。很多程序员不喜欢 GOTO 仅仅是因为这个原因,但该语句还会使代码难于阅读和调试。除非你知道第 11 行写了什么,否则你无法马上说出「GOTO 11」是什么意思。
在 DOPE 中,「T」操作可以让你跳转到给定的行号。但无论是「GOTO 」还是「T」,程序员都不喜欢,因为一旦代码发生变化,你就不知道接下来会跳转到哪儿了。因此,这是一种危险的做法。
但对于初学者来说,按行号跳转是一种简单、易懂的方式。你不需要额外的代码来添加标签。由于大多数新程序员不会编写庞大而复杂的程序,GOTO 的很多危险就消失了。条件语句在 DOPE 中的工作方式与此类似。
唯一的例外是循环。BASIC 中最让我感到奇怪的是它如何处理 FOR 循环。一般来说,循环是你在一个程序中应对重复操作的方式。BASIC 特有的循环就是 FOR 循环。
BASIC 中的多数流控制是用行号来完成的。后来的一些版本允许 if 语句包含表达式,但是达特茅斯的 BASIC 只允许条件跳转。循环有所不同,BASIC 中的一个 FOR 循环包含一个代码块,以 NEXT 结尾。再重申一下,这个怪癖是从 DOPE 中直接继承的,循环包含一个要运行和重新运行的代码块,直到完成。
然而,DOPE 循环也有缺点。这也是我在使用 DOPE 的过程中遇到的瓶颈。Kemeny 说得对,这门语言太简单了,循环就是一个完美的例子。在与 DOPE 打交道的过程中,循环一直是我的眼中钉。在解释器方面,这意味着你需要额外的代码。按块而不是按行号执行代码意味着处理循环的方式必须与该语言中的其他操作稍有不同。连倒计时这种简单的东西都需要额外的代码才能实现。
缺乏字符串也限制了 DOPE 的使用。DOPE 中有类似输出字符串的操作。一种操作允许你打印换行符,另一个操作允许输出一个字符串字面量。这可以用来格式化和标记输出,但是如果没有变量字符串,我们就不能编写非常华丽的代码。我可以用 DOPE 写出经典的「Hello World」,但却无法编写游戏。幸运的是,BASIC 包含字符串。
DOPE 留下了什么?
我发现,DOPE 只适合用在数学领域,在其他领域用处不大。计算包含值的表非常简单,运行一个循环来显示根或平方的列表也很容易。我甚至可以用 DOPE 来处理更大的方程,到目前为止,我写过的最复杂的东西是一个近似 π 的程序。如果你有耐心的话,把方程式转换成简单的运算是有一定禅意的。我一直尝试着做一个数字猜谜游戏,但却遇到了随机数生成的障碍。
这种局限于简单数学的设定未必是坏事。DOPE 是数学家开发的,只是一种向计算机小白介绍计算的方式,而不是一门通用语言。你不会在整个职业生涯中坚持使用这门语言,这也不是 DOPE 创建的初衷。只要能向学生展示什么是计算机、计算机能解决什么问题,以及程序员可能如何解决这些问题,DOPE 的使命就达成了。
那么,为什么没有多少人听过 DOPE 呢?是因为这门语言很失败吗?我不这么认为。我觉得,正是因为它很成功,才会在今天仍然隐身。它名字中的「E」毕竟是实验的意思,在达特茅斯上过一个学期之后,实验就终结了。DOPE 中的想法是有效的,因此 Kemeny 和 Kurtz 才会继续他们的研究,BASIC 是展现 DOPE 成功之处的直接结果。BASIC 在早期的课堂和家庭系统中大受欢迎是因为它足够简单,学习、实现、理解都很简单。DOPE 本身没有延续下来,但它的核心理念已经足够完善,这才有了后来的 BASIC。
原文链接:https://www.vice.com/en/article/5dpq48/tracking-down-dope-the-first-computer-language-for-normal-humans