天天看点

编程语言概要(EOPL)-前言

这本书带你直面计算机编程的基本理念:

   计算机语言的解释器只是另一个程序。

这个听上去很明显,对吧?但是影响是意义深远的。如果你是一个计算理论家,解释器思想会让你回忆起歌德尔的形式逻辑系统的局限性的发现,图灵的通用计算机的概念,以及冯诺依曼的存储程序机器的基本概念。如果你是一个编程者,精通一个解释器的思想是强大力量的源泉。它引发了思维方式的真正转变,你思考编程方式的一种基本改变。

在我学习解释器之前我做了很多编程工作,并且我生产了很多实质的程序。例如,其中一个程序是一个使用PL/I写的大型数据输入和信息检索系统。当我实现我的系统时,我把PL/I视作一个由一些难以接近的语言设计人员建立的固定的规则集合。我认为我的工作就是不修改这些规则,甚至不去深入理解它们,而是从(非常)大量的手册中挑选要使用的这个或那个特性。我从来没有想到过,这种语言的组织方式存在某种潜在的结构,以及我可以去忽略语言设计人员的一些决定。我没有想过如何区创建内嵌的子语言来帮助我组织我的实现,所以整个程序就像一幅巨大而复杂的马赛克,其中每一块都必须被仔细地塑形并放入合适的位置,而不是一组可以被灵活组合的语言。如果你不理解解释器,你仍可以写程序;你甚至可以是一个能干的程序员。但是你不能是一个大师。

为什么一个编程者应该学习解释器,这里有三个理由。

首先,你会在某种情况下去实现解释器,或许不是成熟的通用语言,但是解释器都是一样的。用户可以以一种灵活的方式交流的几乎每个复杂计算机系统都包含了某种构造交互的解释器,例如一个计算机绘图工具或信息检索系统。这些程序可能包含复杂的独立操作,例如在显示器上画一个区域或执行数据库查询,而解释器就像一个粘合剂来让你以一种有用的模式来组合独立的操作。你可以使用一个操作的结果作为另一个操作的输入吗?你可以命名一个操作序列吗?这个名称是局部的还是全局的?你可以参数化一个操作的序列并给它的输入命名吗?等等。无论这些独立的操作多么复杂和优美,这个“粘合剂”的质量往往市最直接决定系统性能的因素。很容易找到独立操作优美但是粘合差劲的程序的例子;回顾一下,我可以看到我的PL/I数据库程序当然也有着差劲的粘合。

其次,即使程序本身不是解释器,也有类似于解释器的重要部分。看看一个复杂计算机辅助设计系统的内部,你很可能发现一个几何识别语言,一个图形解释器,一个基于规则的控制解释器,以及一个面向对象的语言解释器一起工作。构造一个复杂程序的最强大的方式之一就是一个语言集合,其中的每一个提供一个不同的视角,处理程序元素的另一种方式。为正确的目的来选择正确种类的语言,并且理解所涉及的实现权衡:这就是研究解释器的目的。

学习解释器的第三个理由是明确涉及语言结构的编程技术变得越来越重要。今天与设计和操纵面向对象系统中的类层次有关只是这个趋势的一个例子。也许这是一个不可避免的结果,因为我们的程序正变得越来越复杂--更明确地考虑语言可能是处理这种复杂性的最好的工具。再考虑一下这个基本思想:解释器自身只是一个程序。但是那个程序是用某种语言写的,它的解释器自身只是用某种语言写的程序,而这个语言的解释器自身......或许程序和编程语言的完整区别是一个使人误解的想法,未来的程序员不会把自己看作是专门编写程序,而是为每个新的应用程序创建新的语言。

Friedman 和 Wand做了一件具有里程碑意义的工作,他们的书将改变编程语言课程的面貌。他们不止跟你说说解释器;他们会把解释器展现给你。这本书的核心是一系列解释器,从抽象的高级语言开始,逐步明确语言特性,直到我们到达状态机。你实际上可以运行这个代码、学习并修改它,以及改变这些解释器处理作用域、参数传递、控制结构等等的方式。

在使用解释器来研究语言的执行之后,作者展示了如何在不需要运行它们的情况下使用相同的思想来分析程序。在两个新的章节中,他们展示了如何实现类型检查和推断,以及这些特性如何影响现代面向对象语言。

这种方法吸引人的部分原因是作者选择了一个很好的工具--Scheme语言,它将Lisp的统一语法和数据抽象功能与 Algol 的词法作用域和块结构相结合,但是一个强大的工具在主人手中会变得更强大。这本书中的解释器示例都是杰出的典范。实际上,由于它们是可运行的模型,我确信这些解释器和分析器将在未来几年成为许多编程系统的核心。

这不是一本简单的书。掌握解释器并非易事,这是有原因的。与普通的应用程序程序员相比,语言设计人员与最终用户相差甚远。在设计一个应用程序时,您需要考虑要执行的特定任务,并考虑要包含哪些特性。但是在设计一个语言中,你需要考虑人们可能想要去实现的各种应用,以及他们实现的方式。您的语言应该有静态或动态作用域,还是混合的?它应该有继承吗?它应该通过引用还是通过值来传递参数?延续(continuation)应该是显式的还是隐式的?这都取决于你希望你的语言如何被使用,哪类程序容易编写,以及你能负担得起增加难度。(TODO 最后一句不通畅)

而且,解释器是非常精妙的程序。对一行代码简单改变可以在产生的语言行为上造成巨大的差异。不要认为你可以略读这些程序--这个世界上只有极少数人可以扫视下一个新的解释器并据此预测它、在相对简单的程序中会如何运行。所以学习这些程序。如果可以运行它们更好--这是可运行的代码。尝试区解释一些简单的表达式,然后试试更难的。添加错误信息。修改这些解释器。设计你自己的变化。尝试区真正控制这些程序,不要只是得到一个关于如何运行的模糊的感觉。

如果你做到了这点,你会修改改变你的编程视角,以及你作为程序员的视角。你会把自己看作是语言的设计者而不仅仅是语言的使用者,把自己看作是一个选择语言组合规则的人,而不仅仅是其他人所选择规则的跟随者。

第三版附言

上面的前言写在七年前。从那时以来,信息应用和服务已经以在1990年几乎不可能的方式进入世界各地人们的生活中。它们由不断增长的编程语言和编程框架的集合提供技术支持,所有这些都建立在一个不断扩展的解释器平台上。

你想创建一个网页吗?在1990年,这意味着对静态文本和图形进行格式化,实际上就是创建一个只需执行一条“打印”语句的浏览器运行的程序。今天的动态网页充分利用了例如Javascript这样的脚本语言(解释型语言的另一个名字)。浏览器程序可能很复杂,包括对Web服务器的异步调用,Web服务器通常在完全不同的编程框架中运行一个程序,可能使用许多服务,每个服务使用自己的单独语言。

或者您可能正在创建一个机器人来增强您的化身在大型在线多人游戏(如魔兽世界)中的性能,在这个情况下,你可能使用像Lua这样的脚本语言,通过一个面向对象的扩展来帮助表达行为类。

或者,您正在编写一个大型计算集群来在全球范围内进行索引和搜索。要是这样,您可能正在使用函数式编程的map-reduce范型编写程序,以减轻显式地处理各个处理器如何调度的细节。

或者,您可能正在为传感器网络开发新的算法,并探索使用延迟求值来更好地处理并行性和数据聚合。或者探索像XSLT这样的转换网络来控制网页。或者为转换和混合多媒体流设计框架。或者......

这么多的新应用!这么多的新语言!这么多的新解释器!

和以往一样,新手程序员,甚至是有能力的程序员,都可以单独地查看每个新框架,在其固定的规则集内工作。但是创建新的框架需要大师的技巧:理解跨语言的原则,了解哪种语言特性最适合哪种类型的应用程序,并了解如何精心设计使这些语言生动起来的解释器。这些就是你会从本书中学到的技能。

继续阅读