clojure macro宏在运行之前机械展开,定义宏相当于给语言增加新特性,写宏的*原则*:
- 能写成函数就不要用宏(因为写宏没有写函数简单直观,容易写错,需要先在 REPL 中测试一番)
- 只有不得不用时才用宏(性能要求高时比函数调用快,或者需要“代码<->数据”相互转换)
- 精心设计的宏调用比函数调用更 DSL(如实现控制结构、传递 Java方法)
宏与函数
;; 宏正确写法
(defmacro op [x f1 y f2 z]
(list f2 z (list f1 x y)))
(println (op 5 + 2 * 10)) ;; 70
(println (macroexpand '(op 5 + 2 * 10))) ;; (* 10 (+ 5 2))
(println (macroexpand-1 '(op 5 + 2 * 10))) ;; (* 10 (+ 5 2))
(println (clojure.walk/macroexpand-all '(op 5 + 2 * 10))) ;; (* 10 (+ 5 2))
;; 宏错误写法
(defmacro op2 [x f1 y f2 z]
( f2 z (f1 x y)))
(println (op2 5 + 2 * 10)) ;; 2
(println (macroexpand '(op2 5 + 2 * 10))) ;; 2
(println (macroexpand-1 '(op2 5 + 2 * 10))) ;; 2
(println (clojure.walk/macroexpand-all '(op2 5 + 2 * 10))) ;; 2
;; 不使用宏
(defn op3 [x f1 y f2 z]
( f2 z (f1 x y)))
(println (op3 5 + 2 * 10)) ;; 70
(println (macroexpand '(op3 5 + 2 * 10))) ;; (op3 5 + 2 * 10)
(println (macroexpand-1 '(op3 5 + 2 * 10))) ;; (op3 5 + 2 * 10)
(println (clojure.walk/macroexpand-all '(op3 5 + 2 * 10))) ;; (op3 5 + 2 * 10)
说明:
正确的宏写法,需要添加 list,宏用defmacro定义,不用宏写法的函数用defn定义
调试宏,用macroexpand展开
宏符号
` | 原原本本地直译过去,不用`,let语句不被翻译,例如: (let [datastr '{:a 1 :b 2}]) |
~' | 后面的变量被直接翻译过去,例如:(let [~'conn "meta"] (with-mongo ~'conn)) |
'~ | 变量名本身而非值,例如:(defn f1 [x] (println '~x ":" ~x)) (let [a 10] (f1 a)) ;; a:10 |
~@ | 表示多条语句 |
示例1:
(defmacro debug [x] `(println "---" '~x ":" ~x))
(let [a 10] (debug a)) ;; --- a : 10
说明:
'~x 显示变量名,即a
~x 解析为变量值,即a的值 10
示例2:
(defn make-connection [x] (println "in make-connection = " x) x) ;; meta
(defn with-mongo [x] (println "in with-mongo = " x)) ;; meta
(defmacro with-dict
"连接到 meta库的 dict表进行操作"
[& body]
`(let [~'dbname "meta"
~'tbname :dict
~'conn (make-connection ~'dbname)
]
(with-mongo ~'conn)
(println "~'conn = " ~'conn) ;; meta
(println "~'tbname = " ~'tbname) ;; :dict
(println "~@body = " ~@body) ;; meta :dict db-test2' tbl-test2'
~@body))
(let [dbname 'db-test'
tbname 'tbl-test'
dbname2 'db-test2'
tbname2 'tbl-test2'
conn 'conn-sql'
make-connection 'make-conn'
body 'body1']
(with-dict dbname tbname dbname2 tbname2))
运行结果:
in make-connection = meta
in with-mongo = meta
~'conn = meta
~'tbname = :dict
~@body = meta :dict db-test2' tbl-test2'
说明:
make-connection 和with-mongo 是定义的函数,后面传递的是参数,使用 ~'修饰直接翻译过去,即字符串传字符串,:dict 键值也传键值
with-dict 传递多个参数给body,其中dbname tbname 在with-dict 中被重新赋值,因此打印出的结果也为赋值后的最新结果
分享到:
相关推荐
NULL 博文链接:https://clojure.iteye.com/blog/1741375
NULL 博文链接:https://clojure.iteye.com/blog/1742475
backtick, Clojure引用读取器宏作为正常宏的语法 引号提供语法引用( aka quasiquote ) 阅读器宏作为正常宏的Clojure库。动机web服务的反向引用,叫做 syntax syntax,叫做语法引用,使用带有Clojure符号解析的名称...
Clojure入门教程
Clojure学习教程.pdf
Clojure入门教程- Clojure – Functional Programming for the JVM中文版
Clojure入门介绍: Clojure - Functional Programming for the JVM
Clojure学习文档,Clojure-Web开发学习,覆盖了Clojure由浅入深的基本学习
本次演讲中,庄晓丹从AVOSCloud这个完全基于Clojure构建的移动云平台出发,分享Avos团队在Clojure上的实践和经验,为国内Clojure的传播贡献一份力量。
clojure 关键字sheet ,用于快速查看clojure语法及内置form、macro等
Clojure Handbook(2012.11.1)(笔记)
这是Programming Clojure 电子版的 纸质版本在美国亚马逊要到2009年3月才能上架 Paperback: 200 pages Publisher: Pragmatic Bookshelf (March 15, 2009) Language: English ISBN-10: 1934356336 ISBN-13: 978-...
Level up your skills by taking advantage of Clojure's powerful macro system. Macros make hard things possible and normal things easy. They can be tricky to use, and this book will help you deftly ...
Clojure is an opinionated language—it doesn’t try to cover all paradigms or provide every checklist bullet-point feature. Instead it provides the features needed to solve all kinds of real-world ...
Clear, practical Clojure for the professional programmer Professional Clojure is the experienced developer's guide to functional programming using the Clojure language. Designed specifically to meet ...
Practical Clojure Clojure语言书籍
clojure clojure clojureclojure clojure
clojure.tools.macro 编写宏的工具。发布和依赖项信息最新稳定版本:0.1.2依赖项信息: org.clojure/tools.macro { :mvn/version " 0.1.2 " } 依赖项信息: [org.clojure/tools.macro "0.1.2"]依赖项信息: ...
Clojure的标准->宏的扩展,用于构建对主题进行操作的代码块。 安装 SynThread可从clojars获得。 将其添加到您的项目依赖项中: 用法 有关每个宏的具体示例,请参见。 阅读以了解约定和技巧。 总结了提供的宏和功能...