现在的位置: 首页 > 综合 > 正文

深入了解lisp(clojure)-宏

2013年08月24日 ⁄ 综合 ⁄ 共 975字 ⁄ 字号 评论关闭

本文由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。

波浪号:使用在在反引号里面,它的值会被替换。

~@: 替换某个具体元素。

抱歉!评论已关闭.