最近在看一本书《Land OF Lisp》,看了大部分。离前一次看Lisp方面的书刚好三年,用Emacs也有四年了,这期间接触的多是简单的Elisp。总得来说,Lisp的书看起来是比较有趣的,这本也不错,稍微比《Practical Lisp》简单。竟然有个第6.5章,Lambda这么重要,怎么说也要占一章!第八章实现了一个小游戏。Wumpus(Hunt the wumpus)是个古老的游戏,那个年代还没有绚丽画面,只有文字界面。这里游戏的规则是:
1. 地图为一个无向图,玩家控制一个人物在图中行走,目的是寻找潜伏在节点中的一个怪兽。其中要边走边推理,得出怪兽在哪个节点。
2. 还有其他角色,有的节点隐藏着超级蝙蝠,它能把你扔到图的任何位置。节点之间的边可能有警察。
3. 如果你推测出怪兽的位置,向那里射箭,如果射中则胜利,否则输掉。如果你不小心从有警察的边通过了,也死掉。
4. 在怪兽的附近两个距离范围内,会有血气。如果一个点的某条边有警察,这个点会有光晕。
说起来复杂,来看副图。有点像挖地雷那种小游戏。有?符号的为没访问过的点,*为当前点,从14到15遇到警察死掉了。
上周末玩了好几个小时,还挺难胜,主要还是图比较大,游戏一开是整个地图是已经生成了的,要偷懒可以看看。来看看如何用Lisp代码来实现这个程序,程序比较短。首先是如何生成图,需要生成一个随机的连通图。设定节点数目和边的数目,以编号代表节点。random-node:随机地选一个节点。edge-pair:连接两个点表示边。make-edge-list: 重复N次,生成N条边的集合。这个随机图可能不是连通的,下面的代码找出孤立的点集,用一些边连接起来这些孤立的点集,随机图产生完成。第二步向某些点之间加警察,随机的。这其中用了各种mapcar和Lambda,这样的效果使得Lisp程序看起来全是括号。mapcar的意思就是我要在这个列表上面所有的元素上都执行这个Lambda函数。visited列表保存已经访问过的节点,know-city-nodes更新(不是纯函数式编程的风格),know-city-edges根据访问的节点,生成已知的路径,当前已知的用dot画出来。graphviz是个好东西,最近也在学习用这个来画一些流程图,效果挺好的。
乱说说Common Lisp,看了一些这方面的资料,这语言不管有多少牛逼人士簇拥(最近Paul Grahamd的书被翻译了),使用的人还是太少还是有一定的历史原因,早期的实现效率是一个问题,而当实现和硬件都不错了的时候C/C++已经成大局了。另一个很重要的原因是,文档不是很好,我想找个处理图片方面的库,见到一个README文件跟救命稻草似的,打开一看"Do you really need DOCS?"。Lisp的哲学是语言不能给太多限制,甚至做到代码就是数据、数据就是代码,你可以轻而地为语言添加特性,你还可以用宏来写出生成代码的代码。Lisp给了程序员最大的自由来挑战语言的限制,所以会出现如此多种的方言。好的一面是面对特定的问题或许能得到优美而高效率的解决方法,而这个代码对于另外一个程序员来说太难读懂(特别是夹杂了宏的代码),继而难于流传。这里有篇经典的Lisp:Good news,Bad news,作者为早期用Lisp作为开发语言开公司的。
以后看看Haskell吧,这个比较有前途。