Lisp初探
一直以来都想学习Lisp,之前也尝试过几次,可是就是没有真正坚持下来,这次算是勉强学习了一遍,对Lisp的诸多特性有了一个初步的认识。
这次学习Lisp看的书是《实用Common Lisp 编程》,用的IDE是书上推荐的Lispbox。Lispbox其实就是一个配置好的Emacs,加入几个专门学习Common Lisp的插件。之前学习过Elisp,就是GNU Emacs Lisp,是Emacs的扩展语言,也是Lisp的一个方言,与Common Lisp还是有诸多不同。
Lisp是人类历史上第二个高级语言(第一个是Fortran),由人工智能之父麦卡锡于1958年发明。最初Lisp用于符号数据的处理,由于Lisp最初版本内置的许多特性使得Lisp成了当时AI编程的绝佳语言。在Lisp发明后,经过了20多年的发展,出现许多方言和不同实现,为了避免Lisp走向分裂,1981成立的一个Lisp定义了一种叫Common Lisp的标准化的Lisp语言,Common Lisp 旨在结合既有Lisp方言之所长,对Lisp进行标准化。现在Lisp仍然还有众多方言,著名的有:MIT的scheme,作为Emacs的扩展语言的Elisp,作为AutoCAD扩展语言的Autolisp。
回顾完Lisp的历史,下面进入正题,谈谈我对Lisp的认识。算起来本人也学过不下5种语言了,我一直觉得学习一门语言,不仅仅是学习语法,学会应用,更要去探究语言的设计哲学,体会语言设计者的思想。通过对Lisp的初步学习,我总结几个Lisp比较突出的特性。
有一句话是这样描述Lisp的:”可编程的编程语言“。什么意思呢?其实这就是Lisp的第一个特性,或许也是Lisp最与众不同的地方:代码也是数据。也就是说在Lisp里面代码也当成了第一类对象,可以在程序中对语言本身进行处理,这也是所谓的”元编程“的实现形式。当然支持”元编程“的语言很多,比如python、C#等等,不同语言实现“元编程”的方法不一样,比如C#采用的是“反射”,而Lisp采用就是把代码也当成数据。Lisp中实现这个特性的方法叫”宏“,Lisp 宏跟其他语言的宏有着很大的不同,C语言也有宏,但是C语言的宏是基于文本替换的,但是Lisp 宏是把代码作为数据,当成输入,在Lisp宏里面可以使用Lisp所有特性,如果你愿意你甚至可以定义一些辅助函数来帮助宏处理。比如Lisp里面的循环结构采用很多的Loop 其实就是一个宏。
Lisp不仅把数据当成第一类对象,也把函数当成第一类对象,也就是说你可以把函数当成参数进行传递。这样的特性极大提高了语言的灵活性,能够让程序员优雅的编程。Lisp同样支持匿名函数,Lisp实现匿名函数的机制就是大名鼎鼎的lambda表达式。
Lisp本身是支持多种编程范式的,虽然Lisp不是严格意义上的函数式编程语言,但Lisp确实给你提供这种可能,而事实上Lisp列表处理函数全是按函数式编程风格实现的。给我印象最深的是Lisp对面向对象的支持。Lisp用了一种很独特的机制来实现面向对象:广义函数。一般的面向对象的语言,方法是定义在类里面,但是Lisp确不是。Lisp里面你需要定义一个没有具体实现的广义函数,然后对类进行特化实现。当你对某个对象调用函数时,Lisp会自动匹配最合适的实现。Lisp因为这样的机制,还提供了一种所谓的方法组合的特性,即对某个对象调用函数,Lisp可以按特定顺序调用不同的实现。
以上是Lisp给我印象最深的三个特性,当然Lisp还有其他很好的特性,限于篇幅就不再一一列举了。想学习Lisp的,这里推荐几本比较好的书:
《实用Common Lisp 编程》、《On lisp》、《计算程序的构造与解释》。