编程可以从冯·诺依曼风格解放出来么

作者:John Backus


传统程序语言增长的越来越大,不过没有越来越强。在最基本层次的固有缺陷使得它们既臃肿且弱小:它们最初的一次一个单词比编程风格遗传自其共同祖先 —— ·诺依曼计算机,它们将语义密切的连接到状态转换,它们将编程分割到一个表达式的世界(a world of expressions)和一个陈述句的世界(a world of statements),它们不能有效的使用有力的组合形式去从存在的那些构建出新程序,而且它们缺乏有用的数学属性去对程序作推理。


编程的一个替代函数风格可在对就生成程序而言的组合形式的使用中找到。函数式编程处理结构化数据,通常是非重复和非递归的,是分层构造的,不会命名它们的参数,并且让过程声明变得一般上可以应用是不需要复杂机制的。组合形式可以使用高级程序去“以一种在传统语言中不可能的风格”构造更高级的程序。


和函数风格相联系的是程序代数,其变量遍布程序之上,其操作是组合的形式。这种代数可用来转换程序并解方程,其“未知量”是这么一些程序,非常类似于某人在高中代数中变换方程的方式。这些转换是由代数学定律给出的,而且在和程序被写出来的同一种语言中得到执行。组合形式的选择不单单是为了它们的编程力量,也是为了它们和代数学定律相关的力量。代数的一般定理就程序的大类给出了详细的行为和终止条件。


计算系统的一种新类不但在其编程语言中使用函数式编程风格,而且也在其状态转换规则(state transition rules)中使用之。不似 ·诺依曼语言,这些系统语义上和状态是松耦合的 —— 每次主要的计算只发生有一个状态转换。


关键词短语:函数式编程,编程代数,组合形式,函数式形式,编程语言,·诺依曼计算机,·诺依曼语言,计算系统模型,可用计算系统,可用状态转换系统,程序转换,程序正确性, 程序终止,元构成(metacomposition)。


CR 分类: 编程->编程语言->总论,  编程->编程语言->杂论,  计算数学->元理论 ->总论,计算数学->元理论 ->编程理论


介绍(Introduction)

我深深的感谢 ACM 邀请 1977年图灵演讲所给予的,以及这种在演讲中伴随许诺细节谈论的荣誉。那些希望看到该论文总结的读者可以翻到节16,最后一节。


编程语言表现出了一点麻烦。每个成功的语言都吸收了,伴随一点点清理,其前任的所有特征加上的了一点点。某些语言的手册超过了500页;其它的通过使用稠密的形式主义将一个复杂的描述塞入更短的手册。国防部最近就一个委员会设计的语言标准作出的计划可能需要超过1千页的一份手册。每一门新的语言都宣称新而时髦的特征,诸如强类型(strong typing)或结构化控制陈述句(structured control statements),但朴素的事实是,很少有语言让编程对“有理由去说生产和学习使用它们的成本是值得的”来说足够便宜或更可靠(the plain fact is that few languages make programming sufficiently cheaper or more reliable to justify the cost of producing and learning to use them)。


由于大小上的大量增长仅带来了能力上小的增长,所以更小或更精致的语言,比如 Pascal 将继续流行。但有对“一个有力量的方法论来帮助我们思考程序”的极度需要,而且甚至没有传统的语言开始满足这个需要。实际上,传统的语言在我们思考程序时产生了毫无必要的混淆。


编程语言持续朝向它们目前的臃肿条件迈进有二十年了;作为一个结果,研究和发明编程语言已经失去了太多其激动人心的东西。取而代之,其现在是那些“更喜欢和厚厚的详细概略工作(who prefer to work with thick compendia of details)”人的领域,而不是“与新观念相搏斗的(wrestle with new ideas)”人的领域。讨论编程语言类似于中世纪关于“有多少个天使可以在一个针尖上跳舞(the number of angels that can dance on the head of a pin)”的讨论,而取代令人激动的介于本质上概念不同的辩论。


许多有创造力的计算机科学家从发明语言退到发明工具去描述那些语言。不幸的是,他们主要满足于应用他们的精致新工具去研究已经存在的语言之缺点。在检验了传统语言令人震惊的类型结构后,使用由Dana Scott 开发的精致工具,非常叫人吃惊的是,我们中这么多人仍旧被动的满足于取代“积极的搜寻新结构”的那种结构。


这篇文章的目的有两方面;首先,建议在传统语言框架中的基本缺陷使得它们的表现弱小且它们癌一般的增长是不可避免的,第二,建议朝向探索设计一种新的语言的一些替代路线。


第二节 计算系统的模型(Models of Computing Systems)

在每一门编程语言背后有一个其程序控制着的计算系统模型。一些模型是纯抽象的,有些是由硬件来表达的,另外一些是通过编译或解释程序来表达的。在我们更紧密的检查传统语言之前,对“现存模型,作为对当前普遍替换的一个介绍”做一个简单概览是有用的。现存模型可以粗略的用一下概括的标准去分。


2.1 模型标准(Criteria for Models)

  • 2.1.1 基础(Foundations)。该模型有一个精致而紧凑的数学描述么?在证明关于模型行为的有用事实放方面它有用么?或者这个模型是否过于复杂以至于其描述很庞大并没什么数学性的使用?
  • 2.1.2 历史敏感( History sensitivity )这个模型是否包含了存储的一个主张,以至于一个程序可以保存“会影响一个后来程序的行为”那种信息?就是说,这个模型对历史敏感么?
  • 2.1.3 语义类型(Type of semantics)一个程序直到一个终止状态达到前会连续的转换状态(其不是程序)么?陈述是简单的还是复杂的?或者一个“程序”可以相继的被规约到更简单的“程序”以衍生一个最终是结果的(规约语义学)“规范形式的程序(normal form program)”?
  • 2.1.4 程序的清晰和概念上的有用性(Clarity and conceptual usefulness of programs )编程模型清楚的表达了一个进程或计算么?它们体现了那种“帮助我们关于进程的形式化和推理”概念么?


2.2 模型分类(Classification of Models)

使用上述的标准,我们就能大概刻画对计算系统而言的三类模型 ——简单操作模型(simple operational models),应用模型(applicative models),以及·诺依曼模型(von Neumann models)。

  • 2.2.1 简单操作模型(simple operational models) 例子:图灵机,各种自动机。基础(Foundations):精确和有用。 历史敏感( History sensitivity ):有存储,是历史敏感的。语义(Semantics):伴随非常简单状态的状态转换。序清晰度( Program clarity):程序不清晰,而且概念上没有帮助。
  • 2.2.2 应用模型(applicative models)例子: Church  lambda 微积分【参见5】, Curry  combinators 系统【参见6】,  Lisp 【参见17】,在本文献中描述的函数式编程语言。基础(Foundations):精确和有用。历史敏感( History sensitivity ):没有存储,历史不敏感的。语义(Semantics):规约语义,无状态。程序清晰度( Program clarity):程序清晰,而且概念上有帮助。
  • 2.2.3  冯·诺依曼模型(Von Neumann models )例子:·诺依曼计算机(von Neumann computers),传统编程语言。基础(Foundations):复杂,庞大,没有。历史敏感( History sensitivity ):有存储,历史敏感。语义(Semantics):带有复杂状态的状态转换。程序清晰度( Program clarity):程序可以适度的清晰,概念上不是很有用。

上述的分类无可否认是粗燥且可辩论的。一些最近的模型不是很容易嵌入这些范畴中的任何一个。比如,由 Arvind 和Gostelow【参见1】,Dennis 【参见7】,Kosinski 【参见13】开发的数据流语言(data-flow languages )和其它部分的和简单操作模型相契合,不过它们的程序要比在这个类中的那些更早模型更清楚,而且有可能认为某些有规约语义。无论如何作为该领域的一份粗糙地图的这种分类值得讨论。我们只关心 应用模型(applicative models)和冯·诺依曼模型(Von Neumann models )。



第三节 冯·诺依曼计算机(Von Neumann Computers)

为了理解传统编程语言的问题,我们首先来检验一下它们的智力亲种,冯·诺依曼计算机。什么是冯·诺依曼计算机?冯·诺依曼和其它人在三十年前(译注:指上世纪40年代)设想出该东西时,其是一个精致实际统一的观念,其简化了那时存在的若干工程学和编程问题。虽然产生其体系架构的条件有了剧烈的改变,毫无疑问我们仍旧用这个三十年的旧概念来识别“计算机”这个看法。


一台冯·诺依曼计算机在其最简单的形式中有三个部分:一个中央处理器单元(CPU),一个存储,以及一个连接管,其可以将一个单独的字在 CPU  和存储之间作传输(并发送地址给存储)。我建议把这个管子叫做冯·诺依曼瓶颈。一程序的任务是,以某种主要的方式去改变存储的内容;当某人认为这个任务必须“通过把单个字来回的在冯·诺依曼瓶颈中抽取”完全完成,那么它名字的原因就变得明显了。


讽刺的是,在该瓶颈中的一大部分通信量不是有用的数据,只是数据的名字,同时操作和数据只是用来计算这样的名字。在一个字可以通过这个管子得到发送前,其地址必须已经在CPU中了;因此它必须要么通过来自存储的管子发送,要么它是通过某种CPU操作来形成的。如果地址是从存储发送的,那么其地址必须要么已经从存储发送了,要么已经在CPU中形成了,诸如此类。如果,另一方面,地址是在 CPU 中形成的,它就必须要么是通过固定规则(比如,“给程序计数器加1”)形成的,要么是通过“一个通过该管子被发送的指令,于其中其地址必须已经被发送了(by an instruction that was sent through the tube, in which case its address must have been sent)”形成的,诸如此类。


当然在存储中进行大的改变必须有较之“在冯·诺依曼瓶颈中来回的推送巨量的单词(pushing vast numbers of words back and forth through the von Neumann bottleneck)”更少的简单方式。不单单是说,就一个问题的数据通信量而言,这个管子是一个文字瓶颈,而且,更重要的是,其是一个“保持我们去和一次一个字的思考相关联,取代鼓励我们以在手边的任务的更大概念单元术语去思考(that has kept us tied to word- at- a-time thinking instead of encouraging us to think in terms of the larger conceptual units of the task at hand)”的智力瓶颈。因此编程就在本质上对“通过冯·诺依曼瓶颈的单词的庞大通信量”是规划的和详述的,那种通信量的大多数关注的不是重要数据本身,而是哪里去找到它。


第四节 冯·诺依曼语言( Von Neumann Languages)

传统编程语言本质上是冯·诺依曼计算机的高级别复杂版本。我们三十年老的信仰“只有一种计算机(there is only one kind of computer)”,这是我们的信仰“只有一种编程语言(there is only one kind of programming language)——冯·诺依曼语言”的基础。Fortran   Algol 68之间的区别,虽然很明显,不过要比“两者都基于冯·诺依曼计算机编程风格(both are based on the programming style of the von Neumann computer)”这样的事实更少具有重要性。虽然我将传统编程语言指为“冯·诺依曼语言”来取代它们的起源和风格,当然,我不会因为它们的复杂性就责怪伟大的数学家。实际上,有人可能会说我要为那个问题承担一些责任。


冯·诺依曼编程语言使用变量去模拟计算机的存储单元;控制语句control statements精心描述了它的跳转以测试指令;赋值语句assignment statement模拟了它的获取、存储和算数运算。赋值语句是编程语言的冯·诺依曼瓶颈,并让我们保持和计算机瓶颈所在做的是非常类似的一次一个单词的思考方式。


考虑一个典型的程序;在它的中央是若干赋值语句,包含有一些下标变量。各赋值语句产生一个字的结果。程序必须使这些语句得到许多次执行,当改变下标变量时,为了在存储中有期望的总体改变,因为它必须一次只完成一个字。当程序员设计一组控制语句以引起必要的重复时,他因此要关注经过赋值瓶颈的字流(The programmer is thus concerned with the flow of words through the assignment bottleneck as he designs the nest of control statements to cause the necessary repetitions)。


还有,赋值语句将编程分割为两个世界(the assignment statement splits programming into two worlds)。第一个世界包括了赋值语句的右半边(the right sides of assignment statements)。这是表达式的一个整齐有序的世界,这个世界有有用的代数学属性(除了那些经常被副作用所毁坏的属性外 )。最有用的计算就发生在这个世界中(It is the world in which most useful computation takes place) 


传统编程语言的第二个世界是陈述句的世界(the world of statements)。那个世界中的主要状态是赋值语句本身。该语言的所有其它状态之存在,是为了使执行一种必须基于这种原始构造“赋值语句”的计算成为可能。


状态说明是一个无序的世界,只有不多的数学属性。结构化编程可以被视作是对“在这个混沌世界中引入一些秩序(introduce some order into this chaotic world)”的审慎努力,不过在处理“由一次一个字的·诺依曼编程风格生成的,伴随原始性的使用循环,下标,控制分支流”本质问题时,它成就不多。


我们对在·诺依曼语言上的定位继续了·诺依曼计算机的首要地位,且我们对它的依赖使得非·诺依曼语言不经济,并限制了它们的开发。全景的基于非·诺依曼原理有效编程风格的缺位,剥夺了设计师就新计算机体系结构而言的一个智力基础。(就那个主题的简单讨论,见节15。)


应用计算系统对存储和历史敏感的缺乏是“它们没有为计算机设计提供一个基础(they have not provided a foundation for computer design)”的基本原因。还有,大多数的应用系统采用了lambda  微积分的替换操作来作为它们的基本操作。这个操作的能力几乎没有限制,但是对它的完全有效认识对机器的设计师显示出巨大困难。还有,试图对它们引入存储和试图改进其·诺依曼计算机上的效率,应用系统已经趋向于变为沉浸在一个大型·诺依曼系统中了。比如,纯 Lisp 常常被埋在有·诺依曼特征的大型扩展中。结果的这个复杂系统对机器设计师来说没什么帮助。


第五节 冯·诺依曼和函数式程序的比较(Comparison of von Neumann and Functional Programs)

为了就 ·诺依曼语言的某些缺陷取得一个更详细图像,让我们用“将进一步细化的一门简单语言写出的一个函数式语言”去比较下内积(let us compare a conventional program for inner product with a functional one written in a simple language to be detailed further on)。


5.1 内积的冯·诺依曼程序(A von Neumann Program for Inner Product)

c := 0

for i:= 1 step 1 until do

c:= c + a[i] × b[i]


这段程序的几个属性值的关注:

a)其在根据复杂的不可见“状态”上的语句操作。

b)其不是继承的。除了赋值语句的右半边外,其并不从更简单的东西构造起复杂的实体。(然而,更大的程序常常是这样的。)

c)其是动态且重复的。必须要从智力上去理解它的执行。

d)其一次一个字进行的计算是重复的(复值的)以及修改的(变量i)

e)数据的一部分 n 在程序中;因此缺少一般性并只能对长度为 n 的向量工作。

f)它的名字是参数:仅可以用的向量是 a 和 b。为一般化,需要一个过程声明(a procedure declaration)。这些设计复杂的议题(比如,传参 对比 传值)。

g)其“日常开支”操作是由在分散区域(在 for  语句中以及赋值中的下标)的符号来代表的。


这使得不可能将日常开支操作,所有操作中最通常的,加强(consolidate)到单独的、有力的、广泛有用操作中去。因此在编程中这些操作必须总在第一步重新开始(start again at square one),写下 for i:= ... ” 和 for j := ... ” 然后赋值语句会撒上 i's 和j's 


5.2 内积的一个函数式程序(A Functional Program for Inner Product)


Def Innerproduct

 (Insert +)°(ApplyToAll × )° Transpose

 

Or, in abbreviated form:

Def IP  (/+)°(α  × )°Trans.


合成(Composition )(°),插入(Insert)(/), 应用到所有(ApplyToAll)(α)是函数形式,其将现存函数组合以形成新的东西。因此  ° g 是由首先应用 g 然后是 f而得到的函数,α是由 f 应用到参数的所有成员而得到的函数。如果对将 应用到对象 x之后的结果,我们写下了 :x  ,那么我们就可以解释“在评估内积到向量对<<1, 2, 3>, <6, 5, 4>>  的应用”的每一步了,如下:


  IP: << 1,2,3>, <6,5,4>>  =

Definition of IP                       (/+)°(α  ×)° Trans: << 1,2,3>, <6,5,4>>

Effect of composition, °      (/+)::((α  ×):(Trans:<<1,2,3>, <6,5,4>>))

Applying Transpose             (/+):((α  ×): <<1,6>, <2,5>, <3,4>>)

Effect of ApplyToAll, α       (/+): <x: <1,6>, x: <2,5>, x: <3,4>>

Applying ×                      (/+): <6,10,12>

Effect of Insert, /                   +: <6, +: <10,12>>

Applying +                                +: <6,22>

Applying + again                    28


让我们用·诺依曼程序来比较一下这个程序的属性。

a)其仅仅是在它的参数上运行。没有隐含的状态或复杂的转换条件。只有两种规则,一种用来将一个函数应用到其参数,另一种用来获取由一个诸如“合成 ° ,或 应用到所有 α f ”函数形式标记的函数,当一个人理解函数 f 和 ,形式的参数时。

b) 其是层级的,从三个简单的函数(+, ×, Trans)构建起来,以及三个函数形式 f  ° , α 和  /f  

c)其是静态和非重复的,这是在“其结构有助于无需为了理解它而在智力上去执行”意义上说的。

比如说,如果理解了形式 f  ° g 和 α f  的动作及函数 × 和 Trans 的动作,那么就理解了α ×  (α ×)°Trans的动作 了,诸如此类。

d) 其是操作在整个概念单元上的,不是在字上操作的;其有三步;没有一步是重复的。

e) 其没有吸收数据;其是完全一般的;其能就任何一对适当的向量去工作。

f) 其没有命名它的变量;其可以被应用到任何对向量,无任何过程声明或复杂的替换条件。

g) 其使用了在许多其它程序中一般有用的日常开销形式和函数;实际上,只有 + 和 × 不关心日常开销。这些形式和函数可以和其它组合以生成更高级别的日常开销运算符。


14 概括了一类系统,设计用来使上述的带一个简单框架的函数风格编程在一个历史敏感的系统中可用,但是在上述的应用风格可以变为精致而实际的程序语言的基础之前,还需要做许多工作。就目前而言,上述的比较展示了·诺依曼编程语言中存在的一系列严重缺陷,并可以作为“一种对它们的肥胖和孱弱条件负责的努力(in an effort to account for their presentfat and flabby condition)”的一个开始点。


第六节.  语言框架对比可变部分(Language Frameworks versus Changeable Parts)

让我们比较一下编程语言的两个部分。首先,其框架(framework )给出了系统总体规则,其二,它的可变部分(changeable parts),其存在是受到框架期望的,但是其特定行为并没有为框架所说明。比如,for 语句,以及几乎所有其它语句,是 Algol 框架的一部分,但是函数库和用户定义的那些过程是可变部分。因此一门语言的框架描述了其固有的特征,并对其可变特征提供了一个一般环境。


现在假设有一门其有一个“其可容纳作为可变部分的有极大差异的能力特性”的小框架的语言。那么这样的一个框架无需改变自己就可以支持许多不同特征和风格。与这个适宜的可能性形成对照的是,·诺依曼语言总是看上去有一个巨大的框架和非常有限的可变部分。是什么让这发生的?回答关注 ·诺依曼语言的两个问题。


第一个问题源自·诺依曼风格的一次一个字编程,其要求字流来回以达状态,就像流通过·诺依曼瓶颈。·诺依曼语言必须在语义上和状态密切耦合,于其中计算的每一次细节都会改变状态。这种“在语义上和状态密切的耦合”之结果就是,每个特性的每个细节都要构建到状态和其转换规则中去。

因此在研究框架内的细节时,必须明确一·诺依曼语言的每个特性。还有,需要许多复杂的特性以支持基本的弱一次一个字的风格。结果就是一门·诺依曼语言“不可避免的死板而庞大的”框架。


第七节.可变部分和组合形式(Changeable Parts and Combining Forms 

·诺依曼语言的第二个问题是,它们可变部分的表达能力是如此弱小。它们庞大的规模就是这个的明证;毕竟,如果设计师知道所有这些“他现在构建到框架中的”复杂特征,是可以作为可变部分后来添加到进去的,他就不会这般渴望将它们构建到框架中去了。


可能在“提供在一门语言中有力的可变部分”里最重要的元素是“那种‘可一般被使用以从旧的构建出新的过程’的组合形式之可用性(the availability of combining forms that can be generally used to build new procedures from old ones)”。·诺依曼语言只提供原始组合形式,而且·诺依曼框架对它们的使用设置了障碍。


对使用组合形式的一个障碍就是,在·诺依曼语言中表达式世界和陈述句世界之间的分裂(the split between the expression world and the statement world in von Neumann languages)。函数形式自然的属于表达式世界;但是无论它们多么有力,它们只可以构建结果是产生一个字的那些表达式。而在陈述句世界中( statement world ),这些一个字的结果必须并合并到整个结果中。对一个字的组合不是我们真当应该考虑的,但这却是对任何任务以·诺依曼语言编程中的一大部分。为了帮助从单独的字中装配出整个结果,这些语言在陈述句世界(statement world)中提供了一些原始组合形式——for  while if-then-else  陈述句——但这两个世界之间的分裂“阻碍了在任何一个世界中的组合形式去获得它们在一个没有分裂的世界中可以达到的完全能力(prevents the combining forms in either world from attaining the full power they can achieve in an undivided world)”。


·诺依曼语言中使用组合形式的第二个障碍是“在那些语言中使用的精致命名约定,其通过为过程调用所需的替换规则被进一步复杂化(their use of elaborate naming conventions, which are further complicated by the substitution rules required in calling procedures)”。这些都需要在框架中构建一个复杂,从而变量、下标变量、指针、文件名、过程名、传值形参、传名形参、诸如此类,可以合适的得到解释。所有这些名字、约定及规则都和“使用简单的组合形式(the use of simple combining forms)”相冲突。


第八节. APL 对比 一次一个字的编程(APL versus Word-at-a-Time Programming)

由于我关于一次一个字编程已经说了这么多,我现在必需对APL【参见12 说一下。我们欠 Kenneth Iverson 很多,因为他给我们显示了“有这样的程序,其既不是一次一个字也不依赖于 lambda 表达式,并对我们引入了新的函数形式(there are programs that are neither word-at-atime nor dependent on lambda expressions, and for introducing us to the use of new functional forms)”。而且由于APL赋值语句可以存储数组,其函数形式的效应就被扩展到超越了一个单独赋值所能有的效应。


不幸的是,然而,APL还是将编程分隔为一个表达式世界和一个陈述句世界。因此写一行程序的努力部分是由“希望驻留在更有序的表达式世界中(the desire to stay in the more orderly world of expressions)”激发的。APL正好有三个函数形式,叫做内积(inner product),外积(outer product),和约减(reduction)。这些有时候使用困难,它们还不足够,它们的使用被限制在了表达式世界。


最后,APL语义还是和状态过于紧密耦合了。结果就是,虽然该语言有更大的简洁性和能力,其框架仍有·诺依曼语言固有的复杂性和刻板特性。



******(译者略)




第十五节. 对计算机设计的评论(Remarks About Computer Design)

·诺依曼语言的统摄没有给设计师留下多少智力模型去实际的设计超越·诺依曼计算机变种的那种计算机。数据流模型【参见1713】是历史敏感模型的一个替代。基于lambda微积分的替代规则的语言对计算机设计设提出了严肃的问题。Berkling【参见3】已经开发了一种改进的 lambda 微积分,其有三种应用,其让变量的重命名变得没有必要了。他为评估这种语言的表达能力开发了一种机器。为显示“这种语言为有效编程风格打了怎么样的基础,他的机器可以多有效(how sound a basis this language is for an effective programming style and how efficient his machine can be)”的进一步经历是需要的。



Mago【参见15】已经开发了从相同组件(两种)中构造出的一种全新应用机器。它会自底向上的直接评估类似 FP 和其它的应用表达式。其没有·诺依曼存储没有地址寄存器,因此也就没有瓶颈;其能并行的评估许多应用;其内置的操作较之“·诺依曼计算机操作”更类似FP操作。其是我见到过的和·诺依曼计算机最远的分离。


有许多迹象说,编程应用风格可以变得比·诺依曼风格更加有力。因此程序员开发出就“一类新的历史敏感的计算机系统模型,其体现了这样的一个风格,并避免了看上去附着到基于lambda微积分的 系统上的那些内在效率问题(a new class of history-sensitive models of computing systems that embody such a style and avoid the inherent efficiency problems that seem to attach to lambda-calculus based systems)”很重要了。只有当这些模型和它们的应用语言已经证明其对于传统语言的优越性后,我们才会有经济基础去开发新种类的那种可以最好实现它们的计算机。只有在那时,可能,我们才能够在一个不受限于·诺依曼瓶颈的计算机设计中完全利用大规模集成电路。



第十六节. 总结(Summary)

本文前面的十五节可以总结如下。


第一节。传统编程语言是大而复杂的,并且不灵活。它们受限的表达能力不足以成为它们的大小和花费的理由。


第二节。基于编程语言背后的计算系统模型大概分为三类:(a)简单操作模型(比如,图灵机),(b)应用模型(比如,lambda 微积分),以及(c)·诺依曼模型(比如,传统计算机和编程语言)。每一类模型都有一个重要的困难:对类型(a)编程是不可思议的;类型(b)模型不可以从一个程序到另一个程序去保存信息;类型(c) 模型有无用的基础和程序,概念上没什么帮助。


第三节·诺依曼是围绕一个瓶颈来造的:一次一个字的管子连接了CPU 和存储。因为一个程序必须“通过·诺依曼瓶颈来回泵取巨量字(pumping vast numbers of words back and forth through the von Neumann bottleneck)”在存储中作出完全的改变,我们就长出了一种编程风格,其本身关注一次一字经过瓶颈的通讯量,而不是我们问题的更大概念单元。


第四节。传统编程语言是基于过·诺依曼计算机的编程风格。变量 = 存储了元胞;复制语句 =捡取,存储,和算术;控制语句 =跳转和测试指令。符号“:=”是语言上的·诺依曼瓶颈。在传统·诺依曼语言中的编程仍旧关注“通过这个有些更复杂的瓶颈的”一次一个字的通讯量。·诺依曼语言同样将编程分为一个表达式的世界和一个陈述句的世界;第一个是在一个有序的世界,第二个是馄饨的世界,这是一个结构化程序在某重程度上简化了的世界,但是没有触及基本的分裂自身问题,以及一次一个字风格的传统语言。


第五节。本节比较了·诺依曼程序和有关内积的一个基本编程。其显示了前者的若干问题以及后者的优势:比如,·诺依曼程序是重复的,并且一次一个字,仅仅和两个叫做 a 和 b 的长度为n的向量工作,而且仅可通过使用“其有复杂语义的”一个过程声明来一般使用。函数式编程是不重复的,将向量作为单元来处理,更分层的来构建,是完全一般的,并且通过组合为高级日常工作操作来生成“整理工作(housekeeping)”操作。它不用命名其参数,因此就不需要过程声明。


第六节。一种编程语言组成了一个有一些可变部分的框架。一门·诺依曼的框架需要大多数特征构建到里面去;它只可以适应有限的可变部分(比如,用户定义过程)因为在状态中必须有详细的规定,且其转换规则对所有需要改变的部分,如同所有特性要构建到框架中。·诺依曼框架如此不灵活的原因在于“其语义太过精密耦合于状态了(its semantics is too closely coupled to the state)”:一次计算改变状态的每一个细节。


第七节·诺依曼语言的可变部分没有太多的表达能力;这是为何该语言大部分必须构建到框架中的原因。缺乏表现力是由“·诺依曼语言在有效使用组合形式去构造程序时的无能(the inability of von Neumann languages to effectively use combining forms for building programs”造成的,这反过来是由于“表达式和陈述句之间的分裂(the split between expressions and statements)”。组合形式在表达式中正是最好的,不过在·诺依曼语言中,一个表达式只可以产生一个单独的字;因此在表达式世界中的表达能力大多数丧失了。使用组合形式的进一步障碍在于“命名约定的复杂(the elaborate use of naming conventions)”。


第八节。APL是不基于lambda 微积分的第一门“不是一次一个字,并使用函数组合形式 (that is not word-at-a-time and uses functional combining forms)”语言。不过它还是保留了·诺依曼语言的许多问题。


第九节·诺依曼语言没有关于程序推理的有用属性。公理化的和指示化的语义对“描述和理解传统编程(describing and understanding conventional programs)”是精确工具,不过它们只谈论它们并且不可以改变它们的笨拙属性。不似·诺依曼语言,普通代数的语言对“陈述其律则以及将一个等式转化到其解决方案(for stating its laws and for transforming an equation into its solution)”两者都是合适的,所有都在“语言”之中。


第十节。在一门历史敏感的语言中,一段程序可以通过“改变一些由系统保存的存储(changing some store which is saved by the system)”去影响后程序来的行为。任何这样的语言都需要某种状态转换语义(state transition semantics)。但是其不需要语义密切的耦合到“于其中状态随计算的每个细节而改变”状态。提出的“应用状态转换(Applicative state transition,AST)”系统作为对·诺依曼系统的一种历史敏感替代。这些是:(a)松耦合状态转换语义,于其中每次一个主要计算发生一次转换;(b)简单的状态和转换规则;(c) 一个带简单“规约”语义的基本应用系统;以及(d)一门编程语言和状态转换规则,两者都基于基本的应用系统和其语义。下面四节描述了这种方式到·诺依曼语言和系统设计的元素。


第十一节。描述了一类非正式的函数编程(functional programming ,FP)系统,其不使用变量。各个系统是从“对象,函数,函数形式,以及定义”构建起来的。函数将对象隐射到对象中。函数式将已经存在的函数组合以形成新的函数。这一节列出了“原语函数和函数式primitive functions and functional forms)”例子并给了样例程序。该节讨论了 FP 系统的限制和优势。


十二节。描述了一门“代数编程(algebra of programs)”,其变量范围对从一个FP 系统的函数到 其操作 是一个系统的函数式作了涵盖(whose variables range over the functions of an FP system and whose "operations" are the functional forms of the system)。代数二十四法则列表跟在一个例子后面,证明了“一个非重复矩阵乘法程序等价于一个递归程序(the equivalence of a nonrepetitive matrix multiplication program and a recursive one)”。下一子节陈述了“解”两类方程式的两个“扩展理论的”结果。这些解将在这种方程式中的“未知”函数表达为“组成对其行为的一个逐条描述,并立即就终止给出充分必要条件(constitutes a case-by-case description of its behavior and immediately gives the necessary and sufficient conditions for termination)”无限条件扩展。这些结果用于衍生一种“递归理论”以及一种“迭代理论”,其对“某些适度一般和有用的线性等式类(for some moderately general and useful classes of "linear" equations)”提供了现成的扩展。使用这些定理的例子有:(a)对递归和迭代阶乘函数的正确性证明,(b)证明两个迭代程序的等价。一个最后的例子处理“二次方程”,并证明其解是一个幂函数。下一子节给出了两个扩展程序的证明。


相关于 FP 系统的代数与“对lambda  微积分 和其他应用系统相应的代数(the corresponding algebras for the lambda calculus and other applicative systems)”相比较。这种比较显示了,当相比较于多得多的有力的传统系统时,优势来自于多个受限的 FP 系统。提出了一些关于函数到“无限扩展(infinite expansions)”的算法规约问题,并提出了一些关于“在各种‘惰性评估’中使用代数(the use of the algebra in various ‘lazy evaluation’ schemes)”的问题。


第十三节。这一节描述了形式化的函数编程(formal functional programming ,FFP)的,扩展了并使用FP系统的精确行为的系统。它们的语义要比传统系统的更简单,并可通过一个简单的不动点参数来显示一致。


第十四节。这一节比较了Algol 的结构和应用状态转换系统(applicative state transition ,AST)的结构。其使用FFP系统 将一AST 系统描述为其应用子系统。其描述了简单的状态及对系统的转换规则。描述了对AST 系统的一个小的自防护系统程序,以及它如何才能被装入并被“为了文件维护以及为了运行用户程序(for file  maintenance and for running user programs)”使用。该节简要的讨论了 AST 系统及以及“可以被定义和在一个AST系统中使用的”函数命名系统的变种。


第十五节。这一节简要的讨论了在“应用计算机设计,及需要开发并测试更多的实际应用系统模型以作为这样设计的未来基础”上的工作。


感谢(Acknowledgments)

(译者略)




参考(References)

I. Arvind, and Gostelow, K.P. 

A new interpreter for data flow schemas and its implications for computer architecture

Tech. Rep.No. 72, Dept. Comptr. Sci., U. of California, Irvine, Oct. 1975.

2. Backus, J. 

Programming language semantics and closed applicative languages

Conf. Record ACM Symp. on Principles of Programming Languages, Boston, Oct. 1973, 71-86.

3. Berkling, K.J. 

Reduction languages for reduction machines. 

Interner Bericht ISF-76-8, Gesellschaft f'dr Mathematik und Datenverarbeitung MBH, Bonn, Sept. 1976.

4. Burge, W.H. 

Recursive Programming Techniques.

Addison- Wesley, Reading, Mass., 1975.

5. Church, A. 

The Calculi of Lambda-Conversion. 

Princeton U. Press, Princeton, N.J., 1941.

6. Curry, H.B., and Feys, R. 

Combinatory Logic, Vol. 1. 

North Holland Pub. Co., Amsterdam, 1958.

7. Dennis, J.B. 

First version of a data flow procedure language. 

Tech. Mem. No. 61, Lab. for Comptr. Sci., M.I.T., Cambridge, Mass.,May 1973.

8. Dijkstra, E.W. ,

4 Discipline of Programming

Prentice-Hall,Englewood Cliffs, N.J., 1976.

9. Friedman, D.P., and Wise, 

D.S. CONS should not evaluate its arguments

In Automata, Languages and Programming, S. Michaelson and R. Milner, Eds., Edinburgh U. Press, Edinburgh, 1976, pp.257-284.

10. Henderson, P., and Morris, J.H. Jr. 

A lazy evaluator. 

Conf.Record Third ACM Symp. on Principles of Programming Languages,Atlanta, Ga., Jan. 1976, pp. 95-103.

11. Hoare, C.A.R. 

An axiomatic basis for computer programming. 

Comm. ,4CM 12, 10 (Oct. 1969), 576-583.

12. Iverson, K. 

A Programming Language. 

Wiley, New York, 1962.

13. Kosinski, P. 

A data flow programming language. 

Rep. RC 4264, IBM T.J. Watson Research Ctr., Yorktown Heights, N.Y., March1973.

14. Landin, P.J. 

The mechanical evaluation of expressions. 

Computer J. 6, 4 (1964), 308-320.

15. Mago, G.A. 

A network of microprocessors to execute reduction languages. 

To appear in Int. J. Comptr. and Inform. Sci.16. Manna, Z., Ness, S., and Vuillemin, J. 

Inductive methods for proving properties of programs. 

Comm..4 CM 16,8 (Aug. 1973) 491-502.

17. McCarthy, J. 

Recursive functions of symbolic expressions and their computation by machine

Pt. 1. Comm. ,4CM 3, 4 (April 1960), 184-195.

18. Me Jones, P. 

A Church-Rosser property of closed applicative languages

Rep. RJ 1589, IBM Res. Lab., San Jose, Calif., May 1975.

19. Reynolds, J.C. 

GEDANKEN--a simple typeless language based on the principle of completeness and the reference concept. 

Comm.ACM 13, 5 (May 1970), 308-318.

20. Reynolds, J..C. 

Notes on a lattice-theoretic approach to the theory of computation. 

Dept. Syst. and Inform. Sci., Syracuse U., Syracuse,N.Y., 1972.

21. Scott, D. 

Outline of a mathematical theory of computation

Proc. 4th Princeton Conf. on Inform. Sci. and Syst., 1970.

22. Scott, D. 

Lattice-theoretic models for various type-free calculi.

Proc. Fourth Int. Congress for Logic, Methodology, and the Philosophy of Science, Bucharest, 1972.

23. Scott, D., and Strachey, C. 

Towards a mathematical semantics for computer languages

Proc. Symp. on Comptrs. and Automata, Polytechnic Inst. of Brooklyn, 1971.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值