当前位置: 首页 > 科技观察

Lisp语言是怎么来的——Lisp和AI的青梅竹马

时间:2023-03-13 00:55:24 科技观察

LISP语言的历史和一些多余的八卦趣闻其实值得花一本书看。我将在三篇文章中简要介绍LISP的早期历史。说起LISP,就免不了要说到AI(人工智能),那我不妨先八卦一下他们的青梅竹马。如果你翻开任何一本介绍各种编程语言的书,你都不会惊讶地发现,每当提到LISP时,通常的用语都是“LISP是一种适用于人工智能(AI)的语言”。不知道读者看到这句话是怎么理解的,但是我刚上大学的时候,自以为懂一点LISP和人工智能的时候,突然看到这句话的时候,没想到会杀了我。“合适的”。即便后面看了很多遍SICP,也很难想象它为什么“适合”。LISP真的能做到C做不到的事情吗?难道仅仅因为像JohnMcCarthy这样的大神既是AI之父又是LISP之父,所以AI和LISP兄妹一定是天作之合?计算机科学家不是上帝,为什么要创造一个亚当和夏娃,让他们成为一对良配?那么这句话的根据在哪里呢?后来我也看了AI文献,看了过去人工智能的研究情况,结合过去人工智能研究的指导思想,研究人员可用的语言等历史背景,完全是真的。了解这两者的“适合性”。所以,这篇文章不仅仅是八卦,也是我的经验笔记。我们一起回到LISP和AI的童年时代。虽然他们现在看起来关系不是很密切,但是他们小时候可是青梅竹马啊!让机器智能化一直是人类长期以来的梦想,因为这样机器就可以智能地代替人类完成一些任务。第二次世界大战期间高速电子计算机的出现使这个梦想更近了。二战后,计算机并没有完全被军队使用,精英科学家也停止制造原子弹。于是,一下子有了资源和脑筋去研究“智能机器”这种神奇的东西。我们可以随便举出当年研究兴盛的例子:维纳在1948年发表了《控制论》,副标题是《动物和机器的控制和通讯》,里面讲的是生物和机器的反馈,大脑的行为。信息论大师香农于1949年提出下棋机,即针对特定领域的智能机器。同时,1949年加拿大著名神经科学家唐纳德赫布发表了《行为的组织》,开创了神经网络的研究;图灵于1950年发表了著名的《计算机器与智能》一文,提出了著名的图灵测试。建立了这么多学科,这么多学科创始人都在关注智能机器,可见当时确实是这方面研究的黄金时代。二战结束十年后,也就是1956年,这些研究智能机器的研究人员都隐约觉得自己研究的是一个新事物。虽然它与数学、生物、电子相关,但与传统的数学、生物、电子或脑科学不同,因此,建立新品牌成为必然趋势。JohnMcCarthy1956年利用暑假到多特茅斯大学学习(该校也是美国计算机科学发展的圣地之一,例如BASIC语言的发源地),Shannon、明斯基等人(这些人都是年轻人),一起开会,提出了一个很酷的词叫人工智能,这被认为是人工智能学科的正式成立。因为AI是研究智能的机器,学科一旦建立起来,肯定有两个重要的问题需要回答,一个是你如何代表这个世界,一个是计算机如何根据这个世界的知识推导出智能.第一点用行话来说就是“知识表示”的模型,第二点用行话来说就是“智能计算模型”。且不论这两个问题有多不起眼,正是因为当时的研究人员回答了这两个看似微妙的问题,才直接产生了LISP与AI的关系。我们各有一个。先说知识如何表达。人工智能研究与普通编程的区别在于,人工智能的输入数据通常非常多样,没有固定格式。比如一道数学题要解,英文段落要翻译成中文,数独要解,人脸图片要识别。所有这些都需要通过称为“知识表示”的学科表达为计算机可以处理的数据格式。自然地,计算机科学家希望用一种统一的数据格式来表示现实世界中的各种对象,因此设计一种强大而灵活的数据格式是很自然的。这种数据格式是一个链表。在这里,我压倒自己,凭借自己有限的知识,追寻链表为什么恰好是一种理想数据结构的逻辑路线。我想读过SICP的读者应该对链表的灵活性有很深的感受。为了分析链表的长处,我们不妨将其与同时代的其他数据结构进行比较。前面一个系列说过,当时的数据结构非常有限,所以我们不妨比较一下链表和当时使用最广泛的另一种数据结构——数组的优劣。我们都知道数组和链表都是线性数据结构,都各有优缺点,而FORTRAN基本是围绕数组构建的,而LISP是围绕链表实现的。通过研究下棋、几何问题等人工智能问题的表征,我们的读者不难发现,人工智能研究更多地关注符号和逻辑计算,而不是数值计算。比如下棋,很难抽象成纯数字的计算问题。这样一来,只能存储数字的数组就不合适了。当然,我们可以扩展数组,让这些数组元素也可以存储符号。但即便如此,数组也不能存储不同结构的数据。比如象棋中,车马大炮都有自己的规则,存储这些规则需要的结构和cell大小是不同的,所以我们需要一个存储异构数据单元的模块,而不是让每个cell都具有相同的结构。另外,在AI中,有些数据是需要随时添加和修改的。比如象棋,士兵第一步可以走两步,下边可以成后等等,这就要求士兵的规则可以随时修改、增删改查。其他问题也有类似的要求。都需要解除数组维度大小相同的约束,允许动态增减某个维度的大小,或者动态高效地增删数组元素。一旦解除了同构单元格和可以随时增删改查这两个约束,数组就不再是数组了,因为随机访问的特性基本失去了,数组自然就变成了链表。使用链表实现。因此,用链表代替数组作为人工智能的统一数据结构,虽然有天才的想法,但也有实际需要的影响。当然值得一提的是,在像CommonLISP这样偏重于实践而非科研的LISP版本中,数组作为链表的补充,成为基本的数据结构,CommonLISP还可以做图像处理和矩阵处理事情。这个事实进一步说明,采用什么样的数据结构作为基本单元,是由实际需求驱动的。当然,科学家们仅仅证明清单能够代表这些现实世界的问题还不够,还要证明或验证另外两点。第一点,列表表示可以完整表示所有的人工智能问题,即列表结构充分性。只有证明了这一点,我们才敢大胆地使用链表,而不用担心跳出一个问题。现有的链表处理方法根本无法实现人工智能问题。只有这两个问题的答案都是肯定的,列表处理才会成为人工智能的一部分。对于这两个问题,其实并没有确定的答案,只是科学家们的猜想,或者说是一个被普遍接受的研究范式(paradigm)。1976年,构想出LISP前身IPL的两位大神AlanNewell和HerbertSimon终于以追忆历史的方式写了一篇文章。在这篇文章中,他们将当时的范式哲学地概括为:一个物理符号系统具有一般情报行动的充分必要手段。用简单的英语来说,“智能必须依赖于某种符号演算系统,而智能也可以从符号演算系统中推导出来。”实际上,如果你承认这个猜想,或者这个范式,那么你就承认符号演算可以用来实现人工智能。因此,这个猜想使得当时几乎所有的研究人员都把赌注押在了一个通用符号计算系统的实现上,因为如果我们在符号计算的基础上创建一个通用系统,我们就可以利用这个系统实现智能化。上面我们说过,链表强大的表达能力对于这个符号演算系统来说已经绰绰有余了,所以我们只需要关心符号演算是如何实现的,因为如果上面的猜想是正确的,那么链表就可以已经表示了所有的符号,那么我们的整个问题就变成了如何构造这样一个符号演算系统。后面我们可以看到,LISP是通过函数式编程来完成这些微积分规则的构造的。这里需要提醒读者的是,LISP的全称是LIStProcessing,即列表处理,但实际上LISP是由两种相互正交的哲学结合而成的,一种是列表处理,一种是函数式编程。虽然在下文中,我们将介绍将两者无缝结合的S-Expression的优美形式,但为了阐明我们的概念,我想强调列表处理和函数式编程是两个正交的部分。事实上,我们可以用函数以外的其他方式构建列表处理语言。历史上,早在FORTRAN出现之前,AlanNewell和HerbertSimon就在汇编中实现了一种叫做IPL的语言,这种IPL语言是面向过程的,用于列表处理。然后,McCarthy还使用了一系列FORTRAN开头的Subroutines来进行列表处理。比如LISP中的CAR操作,其实就是Register的Addressportion的Content。顾名思义,寄存器的地址单元的内容,即列表的第一个元素(类似于C表达数组的方式,这里寄存器存储的是指向列表第一个元素的指针)。也有很多函数式语言不使用列表作为基本数据单元,比如Scala,它使用对象作为基本数据单元。因此,功能和列表处理不一定相互耦合。那么,LISP选择函数式编程的原因是什么,为什么这种选择更适合当时的AI研究呢?下一节我们将继续介绍当时AI的研究范式、强弱AI之争、函数式编程。当年AI研究的优势。上次说LISP和AI是青梅竹马,简单的说是因为LISP的基本数据单元——“链表”在知识表示上的比较优势。我们说过,AI要处理的数据结构和要描述的现实世界的模型非常复杂,让数组等其他简单的数据结构无能为力,所以“链表”就成了最好的选择。如果我们顺着这条逻辑线往下看,似乎选择LISP这种“列表处理语言”似乎是水到渠成的事情。然而,这个理由并不充分。因为LISP语言不仅仅是列表处理,还有函数式编程等等。反之,如果只有列表处理对AI至关重要,那么用FORTRAN和Algol这两种常见的编程语言和非常流行的传统语言编写一些关于列表处理的函数岂不是更直观方便?那里还有什么?当我们沿着函数式编程的思路走下去时,我们不可避免地会触及AI的早期历史。LISP的特点其实和当时的AI范式是息息相关的。AI范式的演进早在麦卡锡那一代提出AI之前,冯·诺依曼等人就开始研究什么是智能以及如何实现智能。所不同的是,他们更侧重于研究大脑内部的工作机制,并试图通过模拟大脑的工作机制来实现智能。这个学派的理念很明确:人脑是一个标准的智能体,我们只要让计算机模拟人脑的工作方式,计算机就会拥有和人脑一样的智能。对于这个学派的研究人员来说,他们认为大脑的结构和工作机制决定了智力。至于大脑是由脑细胞组成还是由电子线路模拟出来的,对智能来说无所谓。这方面的著名工作是冯诺依曼的《计算机和大脑》论文。在这篇不太学术的文章中,他分析了人脑中神经元的数量和计算机中晶体管的数量,并通过这些量化的比较解释了计算机与人脑之间的差距。另一位当时与冯·诺依曼齐名的神童是控制论的先驱维纳。和冯诺依曼一样,他精通许多学科。和冯诺依曼一样,他是一名数学家,但也精通神经科学和脑科学等学科。一个明显的例子就是在《控制论》一书中,维纳对大脑和神经的分析比比皆是。这种大脑和神经分析的传统始于Cajal(没错,就是写AdviceforaYoungInvestigator的大神),一直延续到后来AI(主要研究神经网络的人工智能学派)的联结主义。然而,当时从脑科学和认知科学的角度分析智力有一个非常大的局限性:脑神经解剖学本身还不成熟。例如,当今的脑科学家在分析脑功能时通常依赖于fMRI和其他神经影像学技术。这些技术可以实时观察大脑中的血氧分布,直接判断执行特定任务时大脑活跃的部位。那时,科学家们只能使用有限的医学影像技术,或者从血管摄影的角度来研究大脑。受当时研究条件的限制,当时的研究人员很难直接观察大脑神经的实时工作状态,分析大脑的实时工作机制。因此,很难对大脑做非常深刻的研究。由于当时医学研究条件的限制,电子学的发展和集成还远远不够,用电子电路模拟大脑产生智能似乎还很遥远。因此,该学派的思想虽然先进,但大部分工作并不是真正用电子电路模拟大脑,而是在探索脑科学和神经科学本身,或者只是用电子电路模拟一些简单的神经动力学行为和小规模神经网络.正是因为联结主义在人工智能本身的实现上并没有太大的进展,所以一直不是人工智能领域的一个新潮研究方向。80年代之前成功实施的人工智能系统很少来自联结主义思想流派。直到20世纪80年代,随着BP算法的重新发现,联结主义才迎来了第二个春天。这时,LISP已经过了20岁的处理。因此,联结主义对人工智能领域使用的编程语言的选择影响不大。符号主义虽然联结主义学派在当时还不是很流行,但AI的研究却如火如荼。这个如日中天的学派采用的是另外一套方法,我们称之为“象征学派”。符号学派的起源可以直接追溯到图灵。图灵对人工智能做了大量的研究,其中最著名的就是“图灵测试”。有一句俗语叫“网上没人知道你是狗”,这句话中,只要把“狗”换成“计算机”,就是简单版的图灵测试。打个更“时髦”的比方,图灵测试就是让电脑或者真人(也叫法官)在线交流,然后让法官猜测跟他说话的是人还是电脑。如果法官分不清人和计算机,我们就认为计算机足以“伪装真实”,具有“与人类相同的智能”,即通过了“图灵测试”。长期以来,图灵测试一直是人工智能研究的圣杯。也就是说,通过“图灵测试”成为了人工智能研究的最终目标。那么,通过图灵测试最直接的方法自然不是让计算机像人脑一样思考,而是只要计算机能够处理对话中使用的单词、句子和符号,就能与人交流对话中的大脑。以同样的方式操纵这些文字和符号,计算机就有希望通过图灵测试。在最极端的情况下,计算机甚至不需要“理解”这些句子的意思就可以通过图灵测试。[有关详细信息,请阅读维基百科上的“中文房间”条目]。有一个开源的聊天机器人叫A.L.I.C.E.,它把我们上面说的“只要能处理和操作符号,就有可能通过图灵测试”发挥到了极致。这个聊天机器人在图灵测试比赛中多次骗过人类评委,“智能”到几乎可以与真人相混淆。然而,就是这样一个非常接近通过图灵测试的机器人,它的基本结构却简单到我们根本无法想象:A.L.I.C.E.的数据库里有一条一条的规则。她说了什么。唯一有点“聪明”的是,有些规则不仅取决于你当前的句子,还取决于你的上一句。【比如在日常对话中,我们先问“你喜欢看电影吗?”,然后再问“什么类型的?”这时候,我们就需要前面的句子来推导出问题是“(喜欢)什么类型的(电影)”]。“中文房间”的例子,以及A.L.I.C.E.的简单结构。机器人,出人意料地表明,即使计算机具有操纵符号的能力并通过了图灵测试,也未必是“智能”的。可惜这句话只是我的后知后觉。在人工智能发展的早期,由于图灵测试的拉动,联结主义的相对弱化和符号主义的繁荣,全世界的人工智能研究都被拉向了一个方向。这个方向很自然,就是“符号处理”。符号处理与LISP补充事实上,正如我们在上一篇文章中提到的,AlanNewell和HerbertSimon认为智能可以从符号演算系统中推导出来,因此以上文字是对符号主义范式的一个历史小注。当我们把LISP放到这段历史中,我们自然会认为什么语言适合做人工智能的问题就变成了“什么语言可以做符号处理”。正如读者所猜测的那样,这个问题的答案是LISP。前面已经介绍了LISP中符号处理的一些优点,这里可以再补充几点。在LISP中,有一种众所周知的统一表达程序和数据的方法,称为S-Expression。这个S其实就是Symbolic的意思。将程序和数据统一视为符号。用现代编程语言的话来说,LISP支持元编程。LISP程序可以处理、生成和修改LISP程序。这个特性,加上函数是一阶对象的事实,使得LISP比任何当代语言都灵活得多。我自己不是LISP用户(甚至不是新手),所以我在这一点上的知识是有限的。但基于我对LISP有限的了解,我认为LISP的灵活性恰好满足了“强大的表达能力”(可以对任何复杂系统进行建模)和“高级抽象能力”。关于第一点,有一句名言是这样说的,当提出任何编程语言的技巧和想法时,总会有专家说LISP早就有这玩意了。具体的例子包括刚刚提到的Themetaprogramming,objectorientedlanguage。这里隐含的是LISP强大的表达能力,使得很多编程范式都可以在LISP中实现,或者找到影子。关于第二点,SICP里面有很多例子,解释的比我的要深刻很多,废话就不用多说了。在上一篇文章中,我提到当你打开任何一本编程书籍时,你都会说“LISP是一种适合AI的编程语言”。那么,如果你和当年的我一样对人工智能的研究和探索感兴趣,你难免会有这样的疑问:“为了学习人工智能,我是否应该学习LISP”?从那时起我有这个疑问已经快8年了。我没有确切的答案,但我知道一些事实。今天的AI范式如果让任何一个面向AI的研究人员推荐几本适合初学者的书,十有八九他会提到《ArtificialIntelligence:AModernApproach》(人工智能,一种现代方法)和《ArtificialIntelligence:ANewSynthesis》”(人工智能,新概述)。这两本书的作者是PeterNorvig和NilsNilsson,他们都是AI领域的老手。如果你是一个对书名很敏感的人,你肯定会想:奇怪,这种书还不是畅销书,难道这两个大牛写书怕卖不出去,所以他们非要加一个“Modern”或“new”来吸引眼球?其实,这个“摩登”,这个“新”,是有很大背景的。事实上,在过去的二十年里,人工智能研究领域发生了几次非常大的范式转变。传统的基于符号的AI方法不再是主流,取而代之的是基于统计和自动推理的多种方法,基于机器学习、群体智慧和大规模数据集的各种研究方法的兴起。这种范式转变对于领域外的人来说似乎是平静的,但实际上AI领域已经发生了翻天覆地的变化。这就是为什么像“新”和“现代”这样的词出现在书名中的原因。遗憾的是,大多数编写编程语言书籍的作者可能并没有完全意识到这一变化,因此他们仍然遵循原有的框架,继续撰写“LISP是一种适合AI的编程语言”这样的断言,并不能完全反映现状。如果算上从事AI研究的研究人员或科学家使用的语言,答案可能五花八门:C/C++/Java用于AISearch,如果模型与矩阵密切相关,则可以使用Matlab进行机器学习,如果统计计算比较多,也可以用R。至于数据挖掘等,语言和库更是五花八门,不能说一种语言占上风。LISP是人工智能的正确语言的教科书神话早已被无数这样的例子打破了。