[转载]我眼中的Common Lisp

原文链接:我眼中的Common Lisp


第一次遇到Lisp这个名字,也许是在大一上计算机科学导论的时候,从书上介绍编程语言的那一章中看到的。那时候记得是在纠结过程式语言与函数式语言的区别,当时总觉得C语言也是函数式的,因为C语言也是有一个个的函数组成的,殊不知道编程语言的范式并不是以这么简单的方式进行区分的。因为好奇,当时还对着书上描述Lisp的短短一段文字看了一会儿,心里很好奇,这个语言到底是长什么样子的。


那时候的自己自学了C很久了,也稍微学过Java以及别的一些和C差不多语法形式的语言。见到那么多的语法和C语言的书写形式都是如此地相似,也就自然而然地以为其实Lisp也是和C差不多的。后来在维基百科上一查看Lisp这份词条,才发现自己当初的想法有多么地幼稚。

见过不少言论说许多人都会Lisp的括号吓到,很不好意思地说,我当初也是这样的。在维基百科上的Lisp词条中,第一次见到了Lisp语言所写的代码,就很奇怪为什么会是如此不自然的写法,也就是前缀表达式。当时还发现了目录中有一个引人注目的章节标题,就是``Lisp的7个公理(基本操作符)''。为什么Lisp会有公理这门子东西呢?那不是数学用语来的吗?总之,第一次遇到Lisp代码时,产生了太多的疑惑和迷茫,几乎陷入了一种不知所措的地步。

记得好像是过了一段时间之后,我突然想学一下这门当时觉得很怪异的语言,于是就在网上找教程。当时找到的还算比较有内容的教程一个是维基教科书上的``Lisp入门'',另一个则是在Ubuntu的Wiki站点上的``Common Lisp Hints''。因为这两个教程的缘故,所以在Lisp的方言当中,Common Lisp阴差阳错地成为了我的所选。不过当时的我也并不怎么明白Common Lisp和Scheme到底有什么关系和区别,因此这也不是刻意的选择。

一开始对各种不同的Lisp实现一点也不在意,也不明白它们之间到底有什么太大的区别,觉得这就像是C语言的各种编译器一样而已,忘记了为什么,就选择了CLISP作为Lisp实现来探索Lisp语言了。当时看的两份教材可以说连入门都不合适,因此看完那两份教材之后,产生了一种Lisp其实也没什么大不了的感觉,因为在这两份教材当中,Lisp强大的功能被提及得实在太少。

后来因为没什么心思和合适的教材,因此就没有再继续学习Lisp了。不过在此之后又在网上看到了一些和Lisp有关的文章,被其中那些述说Lisp强大的文字给弄得斗志激昂,因此决定重新开始学习Common Lisp。当时在网上不停地搜索,陆陆续续地找到了不少的电子文档,有《Pratical Common Lisp》、《On Lisp》、《Common Lisp: A Gentle Introduction to Symbolic Computation》等优秀的读物,开始通过看这些书来学习。一开始看的是《Pratical Common Lisp》,不过因为没什么更基础的知识储备,因此看得挺吃力的,看《On Lisp》那就更痛苦了,最后还是通过《Common Lisp: A Gentle Introduction to Symbolic Computation》这本书让我从比较基础的内容开始了解了一下Common Lisp。

这中间我又弄到了一本《SICP》,也就是大名鼎鼎的MIT所用的计算机科学学生的入门教材《计算机程序的构造与解释》。不过因为其中的内容是基于Scheme的,而且看了前面几节发现习题太难,因此直接半途而废了,大概看了不超过五十页吧。而与Common Lisp有关的书,又弄到了本《ANSI Common Lisp》,也就是Paul Graham所写的那本。不过因为入门用的那些书的内容都要讲解基础知识,因此日渐对书中的内容感到不耐烦,因为不少都看过了,也因此越来越没有耐性看书。

鉴于Lisp的教材在网上如此的稀缺,我慢慢地意识到Lisp是一门非常小众的语言。确实,在我身边,知道Lisp的人可能有那么几个,不过学过Lisp的人应该也就我一个。当然,国内的高校可能比较喜欢教学生们一些所谓的``主流''语言,诸如C/C++、Java之流的。C我倒是非常喜欢,不过C++和Java实在是让我多少有一点反感。不说Lisp,在我身边接触Perl、Python和Ruby之类的语言的人也肯定是超级少的。

其实在没有学会使用Emacs搭配SLIME来进行开发之前,我对写Lisp代码也是充满了恐惧感。还好在《Pratical Common Lisp》一书中,我知道了SLIME的存在,从此我写Lisp代码的活动才没有觉得那么痛苦。即使CLISP可以使用readline库,但是其实和SBCL这种连方向建也不识别的家伙在编辑代码方面相差无几了。

时至今日,走了那么多的曲折路线,总算是学到了Lisp的不少皮毛了,也算是对Lisp这门语言有了自己一定的见解。也许谈不上很深刻,不过却都是在学习、模仿和自己写代码的过程中摸索出来的经验和感受。首先,让我们从Lisp最引人注目的一点入手,那就是它那层层叠叠的括号所包围起来的表达式。按照冰河大哥的说法,Lisp中并非一定要使用前缀表达式,因此,我说,Lisp代码默认是以前缀表达式的形式存在的。既然是前缀表达式,那么和C语言此类的中缀表达式相比,就需要人为地提供表达式的定界符和分隔符。定界符是括号,分隔符是空格,因此也就形成了现在Lisp让人叹为观止的书写方式。前缀表达式其实也有很不错的方面,因为有了Lisp的求值方式的支撑,因此在Lisp当中不需要关心运算符的优先级和结合性。而且前缀表达式使得Lisp中在其它语言中被作为二元运算符看待的+、-、*和/四则运算都可以带任意多的参数,其实,这里应该把它们叫函数。

然后就是Lisp简单而强大的语法。Lisp可以说是一门没有语法的编程语言,非要说有的话,就是要求括号要成对出现而已。Lisp中只有一条求值表达式的规则需要我们遵守,就是对于一条表达式,先对其中的参数进行求值,然后将它们应用在表达式的第一个符号所代表的函数上。当然,Common Lisp里面的求值规则可能还没有Scheme的那么干脆,因为在Scheme语言中,表达式的第一个符号也可以是表达式,而在Common Lisp中则必须为符号或者函数。Common Lisp中还有不少语法糖,例如quote特殊表达式可以写成单引号',function函数可以写成#'等等。

其实在Lisp中,最让人称道的特性,是对数据和过程的表达形式的一致对待。在Lisp当中,(+ 1 1)可能是一段要执行的代码,也可能是一个要处理的数据,这完全取决于这个表达式位于什么位置。如果是在toplevel中,那么它就是一段代码,它将被执行并返回结果2。如果是在quote特殊表达式中,那么它就会被原样返回,当成数据处理。数据和过程的表示形式的一致,使得对函数进行处理的想法变得更加的自然,也催生了使Lisp这门古老的语言在瞬息万变的计算机世界中长久存活下来的特性,那就是这个地球上功能最强大的宏之一,Lisp的宏。

Lisp中的宏可以做非常多的事情,它可以用于创造新的语法,例如在Common Lisp当中没有和C中的switch语句功能一样的存在,那么我就自己定义一个叫做switch的宏,而且这个宏要怎么用,书写形式是怎么样的,完全由我编写者来掌控;宏还可以创造新的范式,据说Common Lisp的面向对象的特性CLOS,就是使用宏在原始Lisp的基础上创建的,而不需要修改编译器和解释器;宏可以最大程度地削减代码中的冗余,只要你知道该怎么写一个宏来帮你消除冗余就可以了,因为宏的特性,所以它可以起到模板的作用,可以生成书写代码的一段代码,因为宏是由编译器和解释器来展开并执行一次的。

宏的特性,在于它不会对它的表达式中的参数立即进行求值,以及需要被执行两次。Common Lisp中的函数表达式,一定会在将参数传递给函数求值之前就把参数全部求值完毕,并且只求值一次。而且函数的返回值不会再由解释器或者编译器求值一次,直接返回给上一级调用者函数。宏则不然,所有参数在传递给宏中的形式参数时,都保持着原来的模样。因此,即使在宏的表达式中不加单引号``引用''表达式,也不必担心表达式可能运算失败返回稀奇古怪的值。宏的参数的求值,完全由宏的编写者决定,他/她可以决定求值哪些参数、求值多少次、哪个先求值哪个后求值等等,一切都具有可控性。而且宏还将在被展开之后送往toplevel再求值一次,因此就可以利用宏,来自动生成一些手写太麻烦,希望由程序代劳的代码,也就是消除冗余和用作模板的功能。总之,Common Lisp当中的宏强大无比,是最锋利的特性之一。

在使用Common Lisp方面,我还远远没有达到专家的地步,毕竟我连《On Lisp》中的不少代码都没有彻底弄懂,怎么想也都是个刚入门的家伙而已。但是我相信Common Lisp是强大的,就像冰河的在他的《超凡脱俗的极限——Common Lisp》一文中所说的那样,``Common Lisp是最强大的编程语言''。Common Lisp已经超越了C语言,成为了我最喜欢的语言,我也很希望能有更多的人领略到Common Lisp的独特风采。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值