从 XML 到 Lisp
之前学 elisp 的时候一直感觉思维转不过来很纠结,看了 The Nature of Lisp,原来正如 Code Complete - Laying the Foundation 章节讲的那样,我们认识新事物总是会借鉴思维里面已有的 Metaphor, 我只用过 C, C++, Java,Python, Objective-C, 也就意味着我基本只有这些语言的 metaphor,都跟 Lisp 差异很大,也难怪了。但也正因为如此,才需要不断的克服自身的排斥心理,去接触更多的新事物。
正如书中所云:
A software metaphor is more like a searchlight than a road map. It doesn’t tell you where to find the answer, it tells you how to look for it. A metaphor serves more as a heuristic than it does as an algorithm.
接触的新事物越多,积攒起来的 metaphor 就越多,“本能” 的触类旁通便也会越频繁,很多科学上的新发现都是把不相干的事物触类旁通的引用到自身领域而突然使人茅塞顿开的。
该文章从 XML 着手,对于这样一个函数
1 | int add(int arg1, int arg2) |
可以将其表示成 XML 格式
1 | <define-function return-type="int" name="add"> |
可以看到,我们能够把任何源代码转为 XML 格式的文档,然后再转为源代码,这就意味着,对于一些语法相近的编程语言来说,可以借助 XML 文档将一种语言写的源代码翻译成另一种,比如 C++ 翻译成 Java。
对于上面的 add 函数,在 XML 文档中,add 到底代表的是 data 还是 code?一方面,它只是位于 XML 文档里的一个单词,没有任何明显的方法去调用它,可以将它解析到 XML 节点树中,并进行一系列的变换,这一点上,它是 data。但另一方面,XML 文档在解析成语法树后被送入编译器,便可以去执行它,或者可以将 XML 文档翻译成 Java 或者 C++ 代码,并且运行它,这是 code。
这意味着 "Code is always data!",反之亦然。
Lisp 的 symbol 不正如此!
另一个例子,用 XML 描述的 copy 功能以及 Java 实现
1 | <copy todir="../new/dir"> |
1 | CopyTask copy = new CopyTask(); |
有了 XML 文档的表述之后,我们更想这样去实现 copy 函数
1 | copy("../new/dir") |
正如 if 和 for 一样,我们实现了一个新的标识符 copy,用来完成 copy 的功能,Java 被扩展了。
然而我们能吗? 我们确实能,可以去 hack 编译器,无非是对抽象语法树和相关功能实现的修改。
如果我们能够很方便的对其抽象语法树进行修改,便可以非常容易的定制特定领域的程序设计语言,即 "Domain Specific Languages"。
将之前的 XML 文档简化
1 | <copy todir="../new/dir"> |
1 | (copy |
这是什么?
Lisp!
该文章还举了 Ant 的例子来加深对代码和 XML 文档转化的理解,并讨论了 "how to write a program that writes programs", 比较了 C macro 和 lisp macro 的实现,最后列举了一系列 Lisp 的基本概念。