第一章:使用过程建立抽象

Building Abstractions with Procedures

心智对简单的想法产生影响的行为主要有这三种:1.将几个简单的想法结合成一个复杂的,复杂的想法就这样形成了。2.第二是将两个想法带到一起,无论简单还是复杂,并把它们放在一起,以便同时观察它们——但不是使它们合为一体——借此它可以获得所有联系的想法。3.第三是把它们和与它们实际在一起的想法分开:这被称为抽象,因此所有的一般想法就这样产生了。

——约翰·洛克,《关于人类认知的随笔》(1690)

The acts of the mind, wherein it exerts its power over simple ideas, are chiefly these three: 1. Combining several simple ideas into one compound one, and thus all complex ideas are made. 2. The second is bringing two ideas, whether simple or complex, together, and setting them by one another so as to take a view of them at once, without uniting them into one, by which it gets all its ideas of relations. 3. The third is separating them from all other ideas that accompany them in their real existence: this is called abstraction, and thus all its general ideas are made.

John Locke, An Essay Concerning Human Understanding (1690)


我们即将学习计算过程的概念。计算过程是居住于计算机中的抽象存在。随着它们的发展,过程操作其他的被称为数据的抽象存在。一个过程的发展受到被称为程序的一系列规则的指导。人们通过创造程序来指导过程。事实上,我们用咒语召唤出计算机的灵魂。

We are about to study the idea of a computational process. Computational processes are abstract beings that inhabit computers. As they evolve, processes manipulate other abstract things called data. The evolution of a process is directed by a pattern of rules called a program. People create programs to direct processes. In effect, we conjure the spirits of the computer with our spells.


计算过程确实很像灵魂对魔法师的概念。它既不能被看到,也不能被触摸到。它根本就不是由物质组成的。然而,它却十分真实。它能执行智能的工作。它能回答问题。它能通过在银行里发放金钱或者在工厂里控制机械臂来改变世界。我们用来召唤过程的程序就像魔法师的咒语一样。它们是由以神秘深奥的编程语言写成、用来描述我们想要进程完成的工作的符号化表达式小心组成的。

A computational process is indeed much like a sorcerer's idea of a spirit. It cannot be seen or touched. It is not composed of matter at all. However, it is very real. It can perform intellectual work. It can answer questions. It can affect the world by disbursing money at a bank or by controlling a robot arm in a factory. The programs we use to conjure processes are like a sorcerer's spells. They are carefully composed from symbolic expressions in arcane and esoteric programming languages that prescribe the tasks we want our processes to perform.


在一台正确运行的计算机上,计算过程能精确又准确地执行程序。因此,就像魔法师的学徒一样,新手程序员必须学会理解和预知他们召唤的结果。即使是程序中很小的错误(通常被称为臭虫或者毛刺)也会造成复杂和意料之外的结果。

A computational process, in a correctly working computer, executes programs precisely and accurately. Thus, like the sorcerer's apprentice, novice programmers must learn to understand and to anticipate the consequences of their conjuring. Even small errors (usually called bugs or glitches) in programs can have complex and unanticipated consequences.


幸运的是,学习编程相比学习法术是相当安全的,因为我们处理的灵魂是被以一种安全的方式方便地收纳起来的。现实生活中的编程需要细致、专业知识和智慧。举例来说,计算机辅助设计程序中的一个小错误可能导致一架飞机或者一座大坝或者一个工业机器人灾难性的自毁。

Fortunately, learning to program is considerably less dangerous than learning sorcery, because the spirits we deal with are conveniently contained in a secure way. Real-world programming, however, requires care, expertise, and wisdom. A small bug in a computer-aided design program, for example, can lead to the catastrophic collapse of an airplane or a dam or the self-destruction of an industrial robot.


软件工程大师有能力组织程序以使他们能合理地确保由此产生的过程能完成预期的任务。他们能事先将他们系统的行为可视化。他们知道如何构建程序以避免意料之外的地问题产生灾难性的后果,而且当问题真的产生时,他们可以调试他们的程序。精心设计的计算系统和精心设计的汽车或者核反应堆一样,是以模块化的方式设计的,因此各个部分都能被分别构建、替换和调试。

Master software engineers have the ability to organize programs so that they can be reasonably sure that the resulting processes will perform the tasks intended. They can visualize the behavior of their systems in advance. They know how to structure programs so that unanticipated problems do not lead to catastrophic consequences, and when problems do arise, they can debug their programs. Well-designed computational systems, like well-designed automobiles or nuclear reactors, are designed in a modular manner, so that the parts can be constructed, replaced, and debugged separately.


使用Lisp编程

Programming in Lisp

我们需要一种用来描述过程的合适语言,因此我们会使用Lisp。就如同我们使用自然语言(英语、法语或日语)表达的日常想法,还有通过数学语言表达的定量现象一样,我们的程序思想会通过Lisp被表达出来。Lisp在20世纪50年代后期作为对特定逻辑表达式(被称为递推公式,是计算的一种模型)进行推理的一种形式主义被发明出来。这门语言由约翰·麦卡锡构想,并建立在他的论文《符号表达式的递归函数及它们在机器上的计算》(麦卡锡,1960)的基础上。

We need an appropriate language for describing processes, and we will use for this purpose the programming language Lisp. Just as our everyday thoughts are usually expressed in our natural language (such as English, French, or Japanese), and descriptions of quantitative phenomena are expressed with mathematical notations, our procedural thoughts will be expressed in Lisp. Lisp was invented in the late 1950s as a formalism for reasoning about the use of certain kinds of logical expressions, called recursion equations, as a model for computation. The language was conceived by John McCarthy and is based on his paper ''Recursive Functions of Symbolic Expressions and Their Computation by Machine'' (McCarthy 1960).


尽管开始时是数学形式主义,Lisp是一门可实践的编程语言。Lisp解释器是用来执行Lisp语言描述的过程的机器。第一个Lisp解释器是由麦卡锡在他在MIT电子研究实验室的人工智能小组和在MIT计算中心的同事和学生的帮助下实现的。$$^1$$Lisp是LISt Processing,即列表处理的缩写。它被设计用于向符号微分和对代数表达式的积分等编程问题的解决提供符号操作功能。为了这个目的,它包含一些新的数据对象,例如原子和列表,这是它与同时期的其他语言最显著的区别。

Despite its inception as a mathematical formalism, Lisp is a practical programming language. A Lisp interpreter is a machine that carries out processes described in the Lisp language. The first Lisp interpreter was implemented by McCarthy with the help of colleagues and students in the Artificial Intelligence Group of the MIT Research Laboratory of Electronics and in the MIT Computation Center.$$^1$$ Lisp, whose name is an acronym for LISt Processing, was designed to provide symbol-manipulating capabilities for attacking programming problems such as the symbolic differentiation and integration of algebraic expressions. It included for this purpose new data objects known as atoms and lists, which most strikingly set it apart from all other languages of the period.


Lisp不是共同谋划的结果,而是以实验性的方式,根据用户需求和对于实际实现的考虑,不正式地逐渐演变而来的。Lisp的非正式演变持续了很多年,Lisp用户的社区也一向抵制发布对该语言的“官方”定义。这样的演变和初步构想的灵活性和优雅性一起,使如今被广泛使用的第二古老的(仅次于Fortran)Lisp语言得以继续适应有关程序设计的最现代的观念。因此,Lisp现在是一个方言的家族。尽管这些方言共享大部分原先的特性,它们可能会和彼此有显著的差异。本书使用的Lisp方言名叫Scheme。$$^2$$

Lisp was not the product of a concerted design effort. Instead, it evolved informally in an experimental manner in response to users' needs and to pragmatic implementation considerations. Lisp's informal evolution has continued through the years, and the community of Lisp users has traditionally resisted attempts to promulgate any ''official'' definition of the language. This evolution, together with the flexibility and elegance of the initial conception, has enabled Lisp, which is the second oldest language in widespread use today (only Fortran is older), to continually adapt to encompass the most modern ideas about program design. Thus, Lisp is by now a family of dialects, which, while sharing most of the original features, may differ from one another in significant ways. The dialect of Lisp used in this book is called Scheme.$$^2$$


由于它实验性的特性和对符号操作的强调,Lisp一开始在数值计算上的表现十分低效,至少和Fortran相比是这样。然而,经年累月,Lisp编译器被开发了出来,它可以把程序翻译成能相当高效地执行数值运算的机器代码。另外,Lisp对于特殊应用十分有效。$$^3$$尽管Lisp还没能改变它低效地令人绝望的旧名声,它已经被应用于很多效率不是重要关注点的地方。例如,Lisp已成为操作系统外壳语言以及编辑器和计算机辅助设计系统的拓展语言的一个选项。

Because of its experimental character and its emphasis on symbol manipulation, Lisp was at first very inefficient for numerical computations, at least in comparison with Fortran. Over the years, however, Lisp compilers have been developed that translate programs into machine code that can perform numerical computations reasonably efficiently. And for special applications, Lisp has been used with great effectiveness.$$^3$$ Although Lisp has not yet overcome its old reputation as hopelessly inefficient, Lisp is now used in many applications where efficiency is not the central concern. For example, Lisp has become a language of choice for operating-system shell languages and for extension languages for editors and computer-aided design systems.


如果Lisp不是一门主流语言,为什么我们要将它作为我们关于编程的讨论的框架呢?因为这门语言具有一些独特的特性,使它成为学习重要编程结构和数据结构,以及连接它们和支持它们的语言特性的优秀媒介。这些特性中最重要的是Lisp对于被称作程序的过程的描述本身可以被表示成Lisp数据,并可以被当作Lisp数据操作。这一点的重要性在于有些强大的程序设计技巧是依靠淡化“被动”数据和“主动”数据之间的传统区别的能力的。如同我们会发现的,Lisp将程序作为数据处理的灵活性令它成为发掘这些技巧最方便的语言之一。将过程表示成数据的能力还使Lisp成为一门编写必须把其他程序当作数据操作的程序,诸如支持计算机语言的解释器和编译器的杰出语言。在这些考虑之上,使用Lisp编程是非常快乐的。

If Lisp is not a mainstream language, why are we using it as the framework for our discussion of programming? Because the language possesses unique features that make it an excellent medium for studying important programming constructs and data structures and for relating them to the linguistic features that support them. The most significant of these features is the fact that Lisp descriptions of processes, called procedures, can themselves be represented and manipulated as Lisp data. The importance of this is that there are powerful program-design techniques that rely on the ability to blur the traditional distinction between ''passive'' data and ''active'' processes. As we shall discover, Lisp's flexibility in handling procedures as data makes it one of the most convenient languages in existence for exploring these techniques. The ability to represent procedures as data also makes Lisp an excellent language for writing programs that must manipulate other programs as data, such as the interpreters and compilers that support computer languages. Above and beyond these considerations, programming in Lisp is great fun.


原文链接

results matching ""

    No results matching ""