编程语言的本质前言,翻译

2020-06-01  本文已影响0人  可乐杯杯hh

这本书带给你面对面的体验,关于计算机编程世界的基础思想:
“程序设计语言的解释器不过是另外一个程序”。
听起来好像是一件很显而易见的事情,是吗?但是它的含义却又是非常深远的。如果你是计算机领域的理论研究人员,解释器的思想实际上要往回追溯到哥德尔发现的关于形式化逻辑系统的局限性(哥德尔不完备定理),图灵通用机器(图灵机),冯诺依曼可存储机器的基本思想(冯诺依曼机)。如果你是一个程序员,掌握了解释器的思想,它会成为你强大力量的来源。它会颠覆你原有的观念,造成你在思考程序设计时的一些最根本的改变。
在我学习解释器之前,我曾编写过大量的程序,也做过一些很牢靠的程序。例如,其中一个是用PL/I编写的大型数据录入和信息检索系统。当我顺利完成这个系统时,我意识到PL/I是由一群有纷争的编程语言设计人员编写的一系列修修补补的语法规则。我感觉我的系统不是很适应这些规则,从而导致它理解起来十分困难,更别提那本(超级)巨大的参考手册了,最后只从里面选两三个能用的特性来编程。这样的经历让我的脑子出现了一个组织编程语言的基本结构,我本来可能会想到重新组织一下这个语言的设计,但是我从没这样去思考过。我不知道如何创建嵌入式的语言帮助我自己的开发,所以这个完整的程序看起来是一个又庞大,又复杂的镶嵌物,一片套着一片,而不是一系列的语言以便在这些系统的部分间可伸缩地组合起来。如果你不理解解释器,你也会这样写程序,你当然可以是一个称职的编码人员,可遗憾的是,你没办法成为一个大师。
程序员应该学习解释器的原因有三个。
首先,你需要一部分技术,它们属于解释器技术的一部分,可能并不是完整且通用的解释器或者语言,但是解释器的实现实际上是一样的思路。大多数人们使用的灵活又复杂的计算机软件系统,例如计算机绘图工具和信息检索系统,包含某些解释器用来构建交互。这些程序可能包含复杂却独特的操作--渲染屏幕的某些区域,执行数据库查询--但是解释器赋予了你组合这些独特的操作到方便的模式里面的能力。你可以使用一个操作的结果作为另一个操作的输入吗?你可以给一系列的操作命名吗?这些名称是局部的还是全局的呢?你可以参数化一系列的操作,然后把名字交给它的输出吗?等等。无论这些特殊操作如何复杂和突出,它通常都是这类系统的质量得到保证的内部决定因素。在程序中找出这些特定的行为是简单的事情,但是组合起来是很丑陋的;再往回看我那个PL/I数据库系统真的是非常糟糕的组合。
第二,即使程序本身不是作为解释器的一部分,它也拥有一些类似解释器的地方。观察计算机辅助设计系统,你会发现几何定义语言,几何交互解释器,基于规则的控制解释器,还有一个面向对象的语言解释器在工作。设计复杂程序最强大的方法就是一系列语言的组合,每一种语言提供了一种关注点,用到这些编程元素不同的工作方式。把合适的编程语言用于对应的目的,理解到使用每种语言的权衡利弊:这就是解释器需要研究的地方。
第三个原因则是为了了解解释器是一种直接关系到编程语言结构的编程技术,它正在变得越来越重要。现在的软件工程化,设计和组织里面,面向对象是这样一种趋势的例子。不可避免的,我们的软件会越来越复杂--直接从语言层面考虑问题也许会是一个比较好的处理复杂性的办法。再次考虑最基本的问题:解释器本身也只是一个程序。但是这个程序是用某些语言编写而成的,解释器的解释器又是另外一些语言编写而成...也许在程序和程序语言之间的距离是一种遐想,未来的程序可能并不是某种语言编写而成的应用程序,而是为了某一个新的应用程序创建一门新的编程语言。
Friedman和Wand已经做出了里程碑的工作,他们的书会改变编程语言课程的面貌。他们不只是告诉你解释器是什么样;他们将它展示给你看。本书的核心是一次编程语言界的旅行,从一个高度抽象的语言,逐渐深入到语言内部的特性直到状态机。你毫无疑问可以运行这些代码,研究它,修改它,然后改变某些解释器的句柄和作用域,控制流等等。
在使用解释器学习语言的执行机制之后,作者会展示如何将相同的想法用于分析程序而无需运行。在接下来的两章里,它们展示了如何实现类型检查和推导,以及这些功能如何与现代的面向对象语言交互。
这种方法之所以吸引人的部分原因在于,作者选择了一个很好的工具--scheme语言,它结合了lisp的词法作用域,垃圾回收和数据抽象功能,还有algol的块结构。但是强大的工具还得要在大师的手上。本书中的实例解释器是杰出的模型。当然,由于它们是可运行的模型,因此我确信考量这些解释器,研究的人会发现自己站在未来几年许多编程系统的核心层面。
这不是一本轻松的书,掌握解释器并不容易,这是有充分理由的。与普通的应用程序员相比,语言设计者是站在高于用户的层次看待问题。在设计应用程序的时候,你要考虑人们可能想要实现的各种功能以及实现方式,他们可能会使用它们。你的语言应该是静态的,还是动态的,还是混合?需要继承吗?它的参数是引用传递还是值传递?续延应该是明确的还是隐式的?这完全取决于你期望使用语言的方式,各个功能应该是易于编写的,并且还能够承载更复杂的任务。
另外,解释器的确是很微妙的程序。简单的更改内部的代码会使得你的解释器行为产生巨大的差异。不要以为你可以轻松看懂并且预测这些程序,世界上很少有人可以看一看新的解释器就能知道它将会发生什么,即使在很简单的程序上。所以学习这些程序最好的办法就是运行它们,这些代码是有效的,尝试解释一些简单的表达式,然后是更加复杂的表达式。添加错误消息,修改解释器,尝试设计自己的变体,试着真正掌握这些程序,不只是对它们的工作模棱两可。
如果这样做,您将改变对编程的看法以及对自己作为程序员的看法。 您会发现自己是语言的设计师,而不仅仅是语言的用户,是选择语言组合规则的人,而不仅仅是其他人选择的规则的追随者。

上一篇下一篇

猜你喜欢

热点阅读