Programming Clojure学习笔记——宏

来源:互联网 发布:mysql视频教程 韩顺平 编辑:程序博客网 时间:2024/06/09 22:39
7.4 宏的分类
Clojure的特殊形式通常只能通过宏来实现,满足使用宏的第二个原则,因此宏的第二个原则也称为特殊形式原则。
特殊形式有一些特殊的功能:
(1) 特殊形式提供了大部分基本的流控制结构,如if和recur等
(2) 特殊形式提供了直接访问Java的途径
(3) 命名的创建和绑定都是通过特殊形式,不管是通过def定义的变量,还是通过let创建一个词法绑定,或者是通过binding创建一个动态绑定。
但是特殊形式不是函数,因此也不具备某些函数的功能:
(1) 不能对特殊形式应用apply函数
(2) 不能将特殊形式赋给一个变量
(3) 不能使用特殊形式作为一个序列库的过滤器

使用宏编写特殊形式通常很困难,但回报也最大。

宏按功能可以分为以下几类:
1. 条件判断(Conditional Evaluation)
因为宏不会立即计算参数值,因此可以用来创建自定义的控制结构,如之前的unless等。

另外注释宏(comment)一般放在源代码文件末尾,用来举例说明API的使用方法,其语法如下:
(comment & exprs)
示例如下:
(comment
(load-file "src/inspector.clj")
(refer 'inspector)
(inspect-tree {:a 1 :b 2 :c [1 2 3 {:d 4 :e 5 :f [6 7 8]}]})
(inspect-table [[1 2 3][4 5 6]]])
)

2. 创建变量(vars)
Clojure的变量都是通过def特殊形式创建的,所有其他东西的创建最后都要调用def。由def衍生出很多其他的特殊形式,如defn,defmacro,defstruct,declare等。

3. 与Java交互
Clojure程序通过.(点), new和set!特殊形式来调用Java,Clojure代码习惯使用宏如..和doto来简化调用Java的形式。

4. 延迟计算
跟延迟有关的宏有lazy-seq, delay, force等。

5. 包装计算
一些宏包装形式集合的计算,在形式的计算之前或之后添加以下特殊的语义,如:
(1) time 启动计时器,计算形式值,然后报告执行时间
(2) let和binding 建立绑定,然后计算某些形式的值,最后解除绑定
(3) with-open 打开文件(或其他资源),然后执行某些操作,最后释放资源

6. 避免匿名函数(Lambdas)
由于历史原因,匿名函数常常被称为Lambdas。有时候宏可以被函数调用替代,函数参数为匿名函数。举例说明实现time功能,用函数实现如下:
(defn bench-fn [f]
     (let [start (System/nanoTime) result (f)]
            {:result result :elapsed (- System/nanoTime) start)}))
要计算某个形式的执行时间,需要编写一个函数包装该形式,然后作为参数传入bench-fn函数,如:
(bench-fn (fn []> (+ 1 2)))
如果通过宏来实现,则不需要新建匿名函数,如:
(bench (+ 1 2))
这里的bench为宏。
原创粉丝点击