为什么编程是表达理解不足的想法的好媒介(1967)

2020-05-10 13:26:48

这是发表在“设计与规划II--设计与通信中的计算机”一章的略微修订版本。

有一种广为流传的信念,认为计算机只能做它们被编程要做的事情。这种错误的信念是基于形式和内容的融合。在描述过程时,严格的语法不必精确。程序员必须非常精确地遵循计算机语法,但他想要表达的内容仍然是自由的。语法是僵化的,是因为使用它的程序员,而不是因为计算机。程序员甚至不需要精确到自己的想法--他脑海中可能有一系列可接受的计算机答案,如果计算机的答案不超出这个范围,他可能会很满意。程序员不必将计算机固定在特定的进程中。在一系列不确定的情况下,他可以要求计算机生成新的程序,或者他可以推荐选择规则,并给计算机关于做出哪些选择的建议。因此,对要执行什么或如何执行的计算机编程不需要非常清晰和精确的公式。

这里提出的论点并不是专门关于设计的,而是关于我们能得到什么计算机来帮助我们做这件事这一普遍问题。由于许多原因,人们习惯于低估可能性。首先,我想警告一下,接受许多相信自己了解情况的人采取的明显温和的立场是有陷阱的。科幻小说家、形形色色的科学家、经济预测家、心理学家,甚至逻辑学家经常告诉我们,计算机永远不会真正思考,这使它成为一个令人信服的故事。我们不能陷入对机器的拟人化思维;它们只做它们的程序所说的,它们不能是原创的或有创意的。(译注:我们不能陷入拟人化的思维方式;它们只能照程序说的做,不能有原创性或创造性。)。

很容易理解为什么一个人文主义者想要对思维过程的模糊性进行研究,因为在这种模糊性和所期望的拟人化的独特性之间有一个简单的非必然结论。但这并不是最重要的。正在讨论的谬论是一种广为流传的迷信,认为除非一个人对要做什么以及如何做有一个极其清晰、准确的表述,否则我们可以编写一个计算机程序来做某事。科学家--甚至是计算机科学家--传播这种观点的次数至少与人文主义者一样多。

关于计算机的局限性,我们被告知的内容通常是这样的:计算机不能创造。它只能完全按照它所说的去做。除非一个过程被精确地公式化,否则你不可能让计算机来完成它。现在,这一点在某种意义上是完全正确的,在另一种意义上则是绝对错误的。(工业和信息化部电子科学技术情报研究所陈皓)。在解释原因之前,有趣的是要注意到-早在计算机出现之前-魔鬼也是这样说的:他只能看起来很有创造力。

玛丽的年龄是安的两倍,当玛丽和安现在一样大的时候。如果玛丽24岁,安多大?

解决了一些问题,但不是全部问题。在那篇文章中,我关心的是如何更进一步,把这种工作扩展到更多用途的普通智力的方向。但就我在这里的目的而言,即使在他们目前的状态下,他们也可以作为足够的榜样,因为虽然他们能处理的能力有限,但他们已经做了足够的事情来扰乱古老的舒适信念。

旧的观点认为,程序只不过是一套严格的规则,规定了在每种情况下到底要做什么。对于安抚初学者编程,或者分析初学者编写的程序,这确实是一个有用的观点。然而,对于更高级的程序来说,虽然从某种意义上说是完全正确的,但可以说房子只不过是建筑材料的排列,或者说书籍只是一长串单词。事实上,对我的一篇《科学美国人》文章(1967年1月1日发表在《计算机评论》上)的评论断言,这些程序是由字典查找例程、搜索和比较函数序列以及排序-合并类型操作组成的。

让我从讨论一种源于好的逻辑学家和坏的哲学家的观点的怀疑态度开始。我们被告知,关于证明逻辑系统自洽的确定性定理具有这样的顺序:发现的过程不可能完全机械化,因此人类总是比机器更有优势。我相信几乎每个读者都听说过哥德尔的定理,而且大多数人都听说过这个所谓的结果。但这不是一个合乎逻辑的结果,因为它是基于粗心的技术疏忽。如果完全适用于解决问题的问题,那么哥德尔定理严格地只适用于完全自洽的逻辑系统。人们并不是如此始终如一,没有任何理由让我们觉得必须沿着这样的路线建造我们的机器。取而代之的是,我们可以,而且已经在做,建造能够容忍相互矛盾的事实断言的机器。要做到这一点,我们必须添加用于解决矛盾的选择规则、用于在不兼容语句之间进行选择的优先级层次结构等等。在伯特伦·拉斐尔1964年的麻省理工学院博士学位论文中描述了这样一个简单的例子。下面是与该程序对话示例:

拉斐尔的知识收集、问答系统表明,当特定事实与一般原则相冲突时,它如何给予更高的优先级。当然,这是一种相当简单的解决矛盾的方法,只有当语句之间的概括性程度有明显差异时,才能使用这一例外原则。当它们处于相同级别时,程序简单地拒绝后面的语句,如下所示:

当然,拉斐尔也可以制定其他的优先权规则。顺便说一句,上面这句话是模棱两可的。拉斐尔的程序通常通过研究所涉及的实体是否已知拥有东西或是事物的一部分等来进行正确的猜测。稍后我将更详细地描述这一点。拉斐尔证明了这样的上下文决策可以编程,这说明了一个更一般的观点,或者更确切地说,它显示了一种与其他方法不同的、更健康的对程序的态度。因此,我们将尝试解释其中的一些。

最普遍和最简单的观点是,计算机程序是对某些数据执行的一系列明确的操作。让我们举一个简单的程序例子:假设X是一个作为输入给出的数字:

在拉斐尔的程序中,当遇到格式为x的语句具有y#34;时,必须决定是";具有";的意思是拥有";的&34;,还是具有作为部分的";:

问题一旦被发现,就会被传送到程序的一部分,以便能够回顾以前发生的所有事情。该子计划根据以下基础做出决定:

(4)如果我们到了这一步,那么我们就知道y已经参与了某件事情的一部分,并被拥有了,我们需要一个更优秀的人。

设U1和U2分别是我们知道在问题(1)和(2)的答案中存在的事物或集合。这些取决于-y。我们现在问:x是U1或U2的成员,还是U2的子体

?如果两个都不是,我们就放弃。如果是其中一个,我们选择相应的结果-#34;的一部分,或者";拥有。如果两者都有,我们再次放弃并要求提供更多信息。正如拉斐尔所说:这些标准很简单,但它们足以使程序对歧义词Has的不同句子中的意图做出相当合理的决定。当然,程序可能会被愚弄而犯错误,例如,在上面的对话中,Dick Has a Chain这句话出现在句子之前,John拥有一条链。然而,一个人在类似的情况下接触到一个生词也会犯类似的错误。这里的要点是,通过参考句子描述中的词的描述来自动解决句子意义中的歧义是可行的,所述句子描述可以通过适当地预先暴露于明确的句子而自动创建。";

因此,程序被指示通过收集先验知识来尝试搜索,以找出x和y是否以一种或另一种方式更密切地相关(如果有关系的话)。该计划的这一部分最好被设想为一个小型审判法庭,或者是一个收集证据和权衡证据的程序。直接把它看作是预先指定的问题解决序列中的一个过程是不好的,而是当程序遇到不一致或歧义时可以咨询的上诉法院。现在,当我们编写一个大型程序时,有许多这样的法院,每个法院都可以在必要时呼吁他人帮助,即使程序员自己已经声明了允许此类上诉的合法原则,但将该程序视为一个序列也变得毫无意义。他可能只是非常不完全地理解,在程序运行过程中,这些程序将在何时何地相互调用。对于一个特殊的法庭,他只粗略地了解了会导致它被传唤的一些情况。简而言之,一旦超过初学者水平,程序员不会简单地编写指令序列。取而代之的是,他们为社交或过程不多的个人写作。尽管我们可能会尝试,但我们很少能提前完全想象到他们互动的所有细节。毕竟,这就是我们需要计算机的原因。

不仅所有恐惧的人文主义者,而且大多数计算机专家都有这样一种巨大的错觉,即编程本质上是一种精确而刻板的表达媒介,这是建立在形式和内容之间的基本混淆的基础上的。如果诗人被要求以十四行为单位写作,这并不会使他们更精确;如果作曲家必须使用所有十二个音调,它不会限制整体形式;如果设计师只能使用四阶表面,没有人会注意到这一点!那么,在(较老的)编程语言的相当僵硬的语法如何提高描述过程的精确度的问题上找到如此一致的看法是很有趣的。你必须在你的计算机语法(句法)上非常精确才能让你的程序运行,这是完全正确的。不允许有拼写或标点符号错误!但是这让你对你的程序要做什么有一个精确的想法,这是完全错误的。在FORTRAN中,如果你想要你的程序调用一些已经写好的过程,你必须使用一种固定的形式,如";转到。你不能说,";或";继续进行,";等等,所以语法是僵硬的。但是,你几乎可以去任何地方,所以内容是免费的。

更糟糕的谬误是假设这种僵硬是因为电脑!这是因为指定语言的程序员!在Bobrow的学生项目中,如果你愿意,你可以一次性地输入,使用总是意味着转到,在简单的情况下,它会允许你使用使用而不是Go。当然,这是灵活性的一个简单例子,但这是大多数人不理解的一点:Fortran的刚度是派生的,如果有什么不同的话,那就是它是派生出来的。这当然是灵活性的一个简单例子,但这也是大多数人不理解的一点:Fortran的僵硬是派生出来的,如果有什么不同的话,那就是它是由Fortran的僵硬派生出来的,这是灵活性的一个很小的例子,但大多数人不理解这一点:Fortran的刚度是派生的。

举一个具有更大灵活性的现代系统的例子,由Warren Teitelman(麻省理工学院博士论文,1966)开发的一种称为Pilot的编程语言,允许程序员通过语言(当前版本)的外部语句在他的程序和语言本身中进行修改。我们通常可以认为这些建议是建议,而不是程序,因为它们是在奇怪的时间编写的,并且通常在默认情况下有条件地应用,或者作为先前建议的结果。下面是一个示例。

告知进度,如果m是Side-1的成员,m是Side-2的成员,并且(countq side-1m)不等于(countq side-1c),则退出。(输入系统的早期建议语句集合已用于生成合理的人性化输入语法。)。

该程序是一种尝试各种范围的启发式搜索

然而,重点不在于放松语法限制,而在于程序中刚刚做出的修改的忠告性质。Tell Progress&34;语句可以在不太了解";Progress&34;已经如何工作或它在";计划中的位置的情况下做出。";它可能已经受到其他建议的影响,人们可能不清楚何时会使用新建议,何时会忽略它。其他一些功能可能已被修改,因此,在某些情况下,进度根本无法评估情况,而且可能会有人被吃掉。如果发生这种情况,局外人会试着猜测原因。

他可以选择(1)彻底理解现有的程序并真正解决问题,或者(2)输入一份新的建议声明,描述他想象中的排便情况,并告诉程序不要将传教士转移到被吃掉的位置。(2)他可以选择(1)彻底理解现有的程序并真正解决问题,或者(2)输入一个新的建议声明,描述他想象中的排便情况,并告诉程序不要将传教士转移到被吃掉的位置。当一个程序通过部分理解的补丁和修复程序的演变而变得强大时,程序员开始失去对内部细节的跟踪,不再能预测会发生什么-并开始希望而不是知道,看着程序就好像它是一个行为不可预测的个体。

这在一些大程序中已经是正确的,但随着我们进入多控制台计算机的时代,它很快就会变得更加尖锐。有了分时系统,大型的启发式程序将由几个程序员开发和修改,每个人在来自不同控制台的不同示例上测试它们,并独立地插入建议。程序将变得无效,但是没有一个程序员会完全理解它。(当然,这并不总是成功的-互动可能会使情况变得更糟,而且可能没有人能够再次修复它!)。现在我们看到了像这样的语句的真正问题,它只做程序员让它做的事情。没有任何一个程序员。

最后,我们来讨论这样一个问题:当我们想要编写一个程序,但是我们对要做什么或如何做的想法没有完全明确的时候,我们应该做什么。让每个人都对这个问题望而却步的不定论非常简单:

大前提:如果我写一个程序,它会做一些特别的事情,因为每个程序都会做一些明确的事情。

其实有两种谬误。首先,说一个人头脑中没有一个特定的结果是不够的。取而代之的是,人们有一个(定义不明确的)可接受的性能范围,如果机器的性能在这个范围内,将会感到高兴。因此,范围越宽,指定程序的纬度就越大。即使写下特定的单词或指令,这也不一定是无效的,因为人们仍然可以自由地将该程序视为一个实例。从这个意义上说,人们可以认为一个特定的书面故事是这个概念的一个实例,这个概念在作者的脑海中可能仍然是不确定的。

这听起来可能像是一种逃避,在一定程度上确实如此。第二个谬误围绕着我必须写下特殊过程的断言。在每一个不确定的领域,凌晨1点可以自由地指定(而不是特定的程序)程序-生成器、选择规则、关于选择的咨询法院等。因此,行为可以有很大的范围-它不需要两次遵循相同的线,它可以覆盖大致相同的容忍度,这是作者的想法。

在这一点上,可能会有最后的反对意见:它正好位于这个范围内吗?请记住,我并不是说编程是表达定义不明确的想法的简单方式!要利用这种媒介无与伦比的灵活性,需要极高的技能--技术、智力和审美。要将程序的行为精确地限制在一个范围内可能非常困难,就像一个编写者需要一些技能来表达一定程度的歧义一样。计算机就像一把小提琴。你可以想象一个小说家先是一台留声机,然后是一把小提琴。他说,后者听起来令人毛骨悚然。这是我们从人文主义者和大多数计算机科学家那里听到的论点。他们说,计算机程序对于特定的目的是好的,但是它们不灵活。小提琴和打字机都不是,除非你学会使用。