Clojure语言十四 常用宏

2015-10-27 10:18
常用宏

infix宏解析人的四则运算书写格式并执行

(defmacro infix
  "Use this macro when you pine for the notation of your childhood"
  [infixed]
  (list (second infixed) (first infixed) (last infixed)))
这么用:
(infix (1 + 1))
; => 2

用macroexpand检查返回的list

上面的例子中,其实经过了去除最后一个symbol,然后再对余下的list求值的过程。

(+ 1 2 10) -> (+ 1 2) -> 3

要想知道最后求值结果出来前的list,可以使用macroexpand. 注意要配合使用' 表示不要求值。

user=> (macroexpand '(ignore-last-operand (+ 1 2 10)))
(+ 1 2)

这样就可以显示宏返回的list,而不是求值。




-> 宏改变从右到左的阅读方式

(defn read-resource
  "Read a resource into a string"
  [path]
  (read-string (slurp (clojure.java.io/resource path))))

这个函数运算的时候会先从最右边的(因为也是最里面)的list开始求值,path -> (clojure...) -> (slurp...) -> (read-string ...), 然后往外层层求值。通过->宏可以将最先求值的放在最上面,写成这样。
(defn read-resource
  [path]
  (-> path
      clojure.java.io/resource
      slurp
      read-string))

每个人有不同的偏好,有些人还是会这样用,为了减少括号的数目和符合自己从左到右或者从上到下的阅读习惯。


binding宏

binding宏用来创建线程专属的变量,在多线程中很常用。

user=> (def ^:dynamic x 1)
user=> (def ^:dynamic y 1)
user=> (+ x y)
2
 
user=> (binding [x 2 y 3]
         (+ x y))
5
 
user=> (+ x y)
2

when宏

可以接受一堆参数,如果条件为真,这些参数都依次被求值,返回最后一个求值的结果。when的实现是用(if 和 (do。

(macroexpand '(when boolean-expression
                expression-1
                expression-2
                expression-3))
; =>
(if boolean-expression
  (do expression-1
      expression-2
      expression-3))




版权声明:本文为博主原创文章,未经博主允许不得转载。