本文由larrylgq编写,转载请注明出处:http://blog.csdn.net/larrylgq/article/details/7395261
作者:吕桂强
邮箱:larry.lv.word@gmail.com
lisp使用特殊操作符来扩展语法,但是在lisp中特殊操作符的数量是固定的,为了解决这个问题lisp引入了宏,宏并不直接做事,而是生成实际的业务代码。
宏的求值过程:接收S-表达式为参数,返回一个lisp展开式(ecpansion),对该展开式求值。
编译过程:在clojure中使用compile编译源文件的时候,将文件中所有宏递归展开成展开式,此时代码中只有函数调用形式和特殊形式。将展开后的代码编译成FASL文件,使用LOAD函数加载时会执行这些编译过的代码。
由于宏不会被直接求值的特性,所以我们定义的宏可以不是标准格式的lisp,每个宏都可以定义自己的语法。
相较于使用核心加上标准库的方式定义的语言,lisp可以通过宏来定义新的语法,并将它放在标准库里,而不是硬编码在语言核心。
当然你也可以将自己会大量复用的代码抽象成宏来使代码更简洁。
宏的结构:名字+形参列表+可选文档字符串+声明+lisp表达式体
一个简单的例子,使用宏实现
(defmacro while "Repeatedly executes body while test expression is true. Presumes some side-effect will cause test to become false/nil. Returns nil" {:added "1.0"} [test & body] `(loop [] (when ~test ~@body (recur))))
当我们这样调用的时候:
user=> (def a (atom 10)) #'user/a user=> (while (pos? @a) (do (println @a) (swap! a dec)))
将会在编译器产生如下代码:
(defn while [(pos? a) (do (println @a) (swap! a dec))]
(loop [] (
(when (pos? a)
(do (println @a) (swap! a dec))
(recur)
)
)))
符号使用:
反引号 :防止宏体内的表达式被evaluate。
波浪号:使用在在反引号里面,它的值会被替换。
~@:
替换某个具体元素。