from http://jlongster.com/Lisp--It-s-Not-About-Macros,-It-s-About-Readhtml
注意:这儿的例子仅仅在 https://github.com/jlongster/outlet 有效,请参考你熟悉的 lisp/scheme 版本中的 read (或者叫其余的什么 forms ) 相关文档。java
我知道这是挖坟,可是此文 http://kuomarc.wordpress.com/2012/02/02/why-i-love-common-lisp-and-hate-java-part-ii-code-examples/ 带了错误的路。其中宏的使用很是使人困惑,用函数会更好点。做者认可了这点,可是他依然这么干了,并且 https://kuomarc.wordpress.com/2012/02/13/why-i-love-common-lisp-and-hate-java-part-iii-macros/ 这篇文章更多的关注了宏,可是依然没有突出重点。python
真理是:真的不是为了(zhuang)宏(bi)而宏的。git
Lisp 的优点更长远。让咱们中止把宏往人脸上糊(而且说宏是惟一更好的抽象方式)。那些人想不通是由于这须要亲自体会。若是只用普通的函数就很合适的状况下还用宏,就更让人困惑了。"Why do you need a macro(宏)? I can abstract the same thing with a function!"github
我不是为了 (zhuang) 宏(bi),我只是为了(ke)读(du)取(xing)web
read 是一个内置的读取对象的函数,在大多数的 lisp 实现中。对象能够是任何原子(数字,字符串,等等),或者一个数据结构好比 list,下面是例子:数据结构
(read "3") ; 3 (read "foo") ; '>>> 'foo (read "\"foo\"") ; "foo" (read "(foo bar baz)") ; (list 'foo 'bar 'baz)
稍等,看看 lisp 的代码,他真的都是 list 组成的:编辑器
(define (foo x) (+ x 1))
一旦你理解了 lisp 代码就是数据 (即:atom 列表),那么你懂了,你能用 read in 来读取 lisp 代码做为数据。因为 lisp 提供了一组函数,优雅的处理列表,解析 lisp 代码忽然就变得很简单了。wordpress
举个栗子:函数
;; program.lisp (define (foo x) (+ x 1)) ;; our parser ;; get-file-contents returns a file's contents as a string ;; (defined elsewhere) (define src (get-file-contents "program.lisp")) ;; src is a string, turn it into data (define forms (read src)) ;; `car` retrieves the first item of a list (display (car forms)) ; 'define ;; `cons` puts an item at the beginning of the list ;; `cdr` gets the rest of the list after the first item ;; `cadr` is a combination, equal to (car (cdr x)) ;; `cddr` is a combination, equal to (cdr (cdr x)) (let ((name-args (cadr forms))) (cons 'lambda (cons (cdr name-args) (cddr forms)))) ;; output: (lambda (x) (+ x 1))
咱们这就写了个把全部的 define 表达式转换为 lambda 表达式。
这应该是另人印象深入的。python js 你怎么作?你须要转换成 ast ,还要学习不少内置方法来解析他。在 lisp 代码就是 ast 结构的数据。
把 read 当作 js 中的 JSON.parse ,js 代码和数据是不一样的, JSON.parse 也不能解析全部的东西。在 lisp 他们都是同样的。
宏到底是啥?它只为了读取打包的漂漂亮亮的数据到正式系统中。你能在编译器上安装宏功能。编译器把程序做为数据读入,用解析并查找宏调用的方式展开他。当找到一个宏调用,编译器把程序做为数据传给宏,这时你能够对程序作任何事情。而后你返回一些数据给编译器,做为代码来解析执行。
若是你依然没被说服,这里,你能写一个 30 行的 lisp 来实现一个宏系统 https://gist.github.com/1712455,你只须要 read ,而且它很简单。
我不想这篇文章变成“Lisp 真是太酷啦”类型的又一篇文章,每一个语言都有他本身的益处,选择你喜欢的。
我只想解释清楚,为何 lisp 族人呼吁宏。他基于 lisp 代码即数据的事实,象征着更强大的一种能力。若是你真的对此好奇,我鼓励你跟随所想,你会发现你想知道的东西。
一些例子,有这些功能的话那么:调试工具变得很容易写(好比一个 40行 tracer https://gist.github.com/1840230 )单元测试能追踪到失败的原始表达式,因此它能展现出错误背后真正所发生的状况。我很难展现出这特性所包含的全部潜力。
我喜欢Paul Graham的文章 “超越平凡” http://www.paulgraham.com/avg.html 下的这个评论:
Viaweb 编辑器的源代码,可能有 20 - 25%的宏。宏比普通的 lisp 函数难写,并且在不必使用宏的地方,宏被视做很差的代码风格。因此每一个宏都是不得不用的时候才写的。也就是说至少 20 - 25% 的代码功能很难用任何别的语言轻易的作到的。不管如何,炮灰猴子可能依然怀疑这神秘的 lisp 能力,这应该会让他感到很古怪。
若是函数比宏更合适,不要考虑这么小的尺度。在更大的尺度上考虑,若是你能写一个解析器来对你的代码作一些疯狂的必要的事情,也许这只要 50 行代码,这是别的语言没法作到的。