本文由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/auser=> (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。
波浪號:使用在在反引號裡面,它的值會被替換。
~@: 替換某個具體元素。