Common Lisp vs Python 学习难度

Common Lisp 有多复杂?

《Common LISP The Language Second Edition》包含了 Common Lisp 语言的所有核心内容,但这些内容不包括:网络库、多线程、系统操作等等,这本书有 1,096 页左右。下图是 A4 纸打印装订后和《算法导论 第三版》的厚度对比:

1.png

同样只包含语言核心内容的《Learning Python, 5th Edition》就已经超过了 1,500 页了,覆盖了 Python2.7 和 3.3 的内容。而 Common Lisp 整体变化几乎是微乎其微,标准也有很多年没有做过修正,甚至 Paul Graham 在 1995 年写的 400 多页的《ANSI Common LISP》至今仍是 Common Lisp 入门的主要书籍(这 400 多页,附录、索引就占了很多)。而 Python 语言却越来越走向复杂的路线,对 Common Lisp 而言,就算要增加新特性,无非就是表面看上去多了几个“函数”而已。

所以,学习一门经久不衰的语言是很值得的,更何况天下语言大多带有 Lisp 基因?

那学习 Lisp 的难度在哪儿?无非就是思维的转变。

*比如饱受争议的括号太多。*其他很多语言不仅有小括号,还有中括号和大括号,以及逗号,甚至分号。而 Python 也是满篇的缩进符,大多人会认为 Python 的缩进会让可读性更好,正解,读 Common Lisp 代码,看的也是缩进,而不是括号。比如下面这段代码:

(dolist (i '(1 2 3))
  (print i))

很明显可以从缩进看出 print 是 dolist 循环体中的代码,良好的 Lisp 编辑器都可以很完美地帮你解决缩进问题。有人又会说,那用记事本写的 Lisp 代码怎么办?我想也没几个人会用记事本写 Python 吧?就算去掉缩进,Lisp 代码仍旧能正确执行,而 Python 没有了缩进,就没法正确执行了,有个好玩的真实故事:以前有个哥们花了几千块钱从老外手中买了一个漏洞利用脚本,脚本是 Python 写的,老外在给他时把缩进全部删了,导致他花了很长时间才缩进正确,脚本才能执行……

*不习惯前缀表达式*也是被大多人不能接受的原因,而前缀表达式是 Lisp 非常强大的地方。

它让 Lisp 解析器工作起来更加简单:

(+ 1 1)

Lisp 解析器把第一个“+”当作函数,其余当作参数。而其他中缀的语言要完整这个加法运算,还需要建立语法抽象树,运算符是运算符,关键字是关键字,函数是函数,分得很明细。在 Lisp 里,这些用起来感觉全是函数一样,就像上面的代码里“+”不是运算符一样。这又给我们带来个很强大的特性,看看下面这段 Common Lisp 代码:

(reduce #'+ '(1 2 3))

注:Common Lisp 是 Lisp-2,所以为了表达函数,需要加“#+”开头

Python 里可以这么写吗:

reduce(+, [1, 2, 3])

显然不行,Python 中“+”是运算符,上面代码执行会报错:

In [4]: reduce(+, [1, 2, 3])
  File "<ipython-input-6-6ffbf65f8bb7>", line 1
    reduce(+, [1, 2, 3])
            ^
SyntaxError: invalid syntax

你得这样做:

In [10]: reduce(lambda a, b: a + b, [1, 2, 3])
Out[10]: 6

或者更简单点:

In [11]: import operator

In [21]: reduce(operator.add, [1, 2, 3])
Out[26]: 6

并且前缀表达式还解决了运算符优先级的问题,你不用像写中缀表达式的语言那样停顿下来思考优先级。

学习 Python,你得熟悉它的语法,包括怪异的语法。Python 随着不断地改进,语法和自身特性也会有变动,这也引发了兼容性的问题。而在 Common Lisp 中只有括号和前缀,改动几乎很少,如此简单优美的表达方式也可以让你自由定义新功能,新的功能使用起来和本身定义好的无差别,所以很多古老的 Lisp 代码至今也能运行。

接着就是**编程范式**问题,大多数人以为 Lisp 就是函数式编程语言,学习 Lisp 就要学习函数式编程。实际上不对的,在强大的表达方式下,Lisp 是多范式的编程语言。Common Lisp 和 Python 一样,它支持面向对象、面向过程和函数式,只是说函数式编程是 Lisp 常用的编程范式。更悬一点地说,就算某一天某个新的编程范式成为主流,想要 Common Lisp 支持它,你可以自己去定义。《On Lisp》这本书中,作者就用 Common Lisp 实现了一个面向对象系统。

学习 Python 时,你可能会去学元编程,而在 Lisp 中有更强大的宏;使用类,还得学习面向对象,不仅要学会如何组织类,还要学会设计模式,这种思维模式在 Common Lisp 中仍可用。Python 也有很多地方都是借鉴了 Lisp,学习 Lisp 后,Python 水平也会跟着上去的,甚至可以用 Lisp 的思维写 Python 代码。

最后,*关于开发环境*,无论使用 Python 还是 Common Lisp,我们都享有 REPL 。Python 有很多好用的商业和免费的 IDE,而 Common Lisp 主要的开发环境是 Emacs+Slime,一些商业版的 Common Lisp 系统也有他们自己的 IDE,另外 Vim 也可以,但大多数还是用的 Emacs。虽然说学习 Emacs 又是一个很高的成本,但是,在学会 Common Lisp 和 Emacs 的同时,等同又送了你 Elisp,因为 Elisp 和 Common Lisp 非常像,这收获是非常丰富的。

所以,综合来说,我觉得 Python 学起来也不简单,Common Lisp 学起来也不难。并且学习 Common Lisp 收获是很丰富的——在学习过程中可以不断感受着,唯独需要的就是时间和耐心,去习惯那种思维,吸收 Lisp 中的思想——终身受用。学习 Python,你会的仅仅是 Python,而学会了 Common Lisp,你会的不仅是 Common Lisp。