clojure macro宏在运行之前机械展开,定义宏相当于给语言增加新特性,写宏的*原则*: 
  • 能写成函数就不要用宏(因为写宏没有写函数简单直观,容易写错,需要先在 REPL 中测试一番)
  • 只有不得不用时才用宏(性能要求高时比函数调用快,或者需要“代码<->数据”相互转换)
  • 精心设计的宏调用比函数调用更 DSL(如实现控制结构、传递 Java方法)

宏与函数

[python] view plaincopy print?
  1. ;; 宏正确写法
  2. (defmacro op [x f1 y f2 z]
  3. (list f2 z (list f1 x y)))
  4. (println (op 5 + 2 * 10))                   ;; 70
  5. (println (macroexpand '(op 5 + 2 * 10)))                     ;; (* 10 (+ 5 2))
  6. (println (macroexpand-1 '(op 5 + 2 * 10)))                   ;; (* 10 (+ 5 2))
  7. (println (clojure.walk/macroexpand-all '(op 5 + 2 * 10)))    ;; (* 10 (+ 5 2))
  8. ;; 宏错误写法
  9. (defmacro op2 [x f1 y f2 z]
  10. ( f2 z (f1 x y)))
  11. (println (op2 5 + 2 * 10))                  ;; 2
  12. (println (macroexpand '(op2 5 + 2 * 10)))                    ;; 2
  13. (println (macroexpand-1 '(op2 5 + 2 * 10)))                  ;; 2
  14. (println (clojure.walk/macroexpand-all '(op2 5 + 2 * 10)))   ;; 2
  15. ;; 不使用宏
  16. (defn op3 [x f1 y f2 z]
  17. ( f2 z (f1 x y)))
  18. (println (op3 5 + 2 * 10))                  ;; 70
  19. (println (macroexpand '(op3 5 + 2 * 10)))                    ;; (op3 5 + 2 * 10)
  20. (println (macroexpand-1 '(op3 5 + 2 * 10)))                  ;; (op3 5 + 2 * 10)
  21. (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:

[python] view plaincopy print?
  1. (defmacro debug [x] `(println "---" '~x ":" ~x))
  2. (let [a 10] (debug a))             ;; --- a : 10

说明:

'~x  显示变量名,即a

~x 解析为变量值,即a的值 10

示例2:

[python] view plaincopy print?
  1. (defn make-connection [x] (println "in make-connection = " x) x)    ;; meta
  2. (defn with-mongo [x] (println "in with-mongo = " x))   ;; meta
  3. (defmacro with-dict
  4. "连接到 meta库的 dict表进行操作"
  5. [& body]
  6. `(let [~'dbname "meta"
  7. ~'tbname :dict
  8. ~'conn (make-connection ~'dbname)
  9. ]
  10. (with-mongo ~'conn)
  11. (println "~'conn = " ~'conn)   ;; meta
  12. (println "~'tbname = " ~'tbname)   ;; :dict
  13. (println "~@body = " ~@body)       ;; meta :dict db-test2' tbl-test2'
  14. ~@body))
  15. (let [dbname 'db-test'
  16. tbname 'tbl-test'
  17. dbname2 'db-test2'
  18. tbname2 'tbl-test2'
  19. conn 'conn-sql'
  20. make-connection 'make-conn'
  21. body 'body1']
  22. (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 中被重新赋值,因此打印出的结果也为赋值后的最新结果

Clojure 学习入门(11)- 宏 macro相关推荐

  1. Clojure 学习入门(6)- 函数定义

    一.创建函数:  fn: fn是一个宏,用于定义一个简单的函数,如下:  [python] view plaincopy print? user=> (fn [] "hello&quo ...

  2. Clojure 学习入门(6)—— 函数定义

    一.创建函数: fn: fn是一个宏,用于定义一个简单的函数,如下:  user=> (fn [] "hello") #<user$eval375$fn__376 us ...

  3. Clojure 学习入门(16)- 正则表达式

    一.创建正则表达式  re-pattern函数:  函数 (re-pattern) 接受一个字符串参数,返回一个正则表达式样式(java.util.regex.Pattern类的实例).这个样式能用于 ...

  4. Clojure 学习入门(13)- binding

    Clojure里面是不支持变量的.Binding跟变量有点像,但是在被赋值之前是不允许改的,包括:全局binding, 线程本地(thread local)binding, 以及函数内的本地bindi ...

  5. Clojure 学习入门(1) - 学习资料

    转自:http://blog.csdn.net/ithomer/article/details/17225813 Clojure(发音类似"closure",['kləʊʒə(r) ...

  6. Clojure 学习入门(15)- 条件判断

    一.标准的流程控制  if:  将一个判断表达式作为它的第一个参数进行求值.如果求值为true,那么就返回它的第二个参数(相当于"then"子句)的求值结果.如果结果为false( ...

  7. Clojure 学习入门(14)- 循环控制

    Clojure 基于函数的流程控制  repeatedly 字面意思为重复函数.一般的用法如下: user=> (repeatedly 5 #(rand-int 11)) (6 8 2 6 6) ...

  8. Clojure 学习入门(7)- 连接mysql

    Clojure的contrib包中实现了对现有JDBC的封装,在wiki上有连接,该页面上包含了对不同的数据库的连接方法和基本的操作,但是这个页面上没有提供足够的信息,足够一个初学者能够使用Cloju ...

  9. Clojure 学习入门(3)- 数字类型

    一.算术运算  加法+:加法函数(+)接受任意数值类型的参数,返回它们的和:没有参数时返回0.  [python] view plaincopy print? $clojure Clojure 1.2 ...

最新文章

  1. 【Kotlin】Kotlin 语言集合中的高阶函数详解 ( 数据类 data class | maxBy | minBy | filter | map | any | count | find )
  2. STM32F103 CAN中断发送功能的再次讨论
  3. opython3l_Python从小白到攻城狮(3)——列表和元组,到底用哪个?
  4. C语言gauss elimination高斯消元法算法(附完整源码)
  5. linux锐捷认证成功无法上网,win7系统锐捷认证成功但是却无法上网的解决方法
  6. oracle恢复drop建的表首次,案例:Oracle dul数据挖掘 没有备份情况下非常规恢复drop删除的数据表...
  7. D-query SPOJ - DQUERY (主席树)
  8. 阿里云ECI如何6秒扩容3000容器实例?
  9. spring中配置quartz定时器
  10. asp.net mvc 中直接访问静态页面
  11. ibatis学习四---执行流程浅析
  12. 阿里 Maven仓库
  13. 樊登读书会终身成长读后感_樊登读书会创始人演讲《知识爆炸时代如何终身成长》...
  14. 英特尔核心显卡控制面板设置自定义分辨率
  15. Paper intensive reading (二十五):Fecal Viral ...Virion-Enriched Metagenomics and Metatranscriptomics
  16. 打字母案例完整版(C#)
  17. Navicat Premium 12.0.22安装与激活
  18. Atcoder abc A~E
  19. 苹果手机有便签吗?苹果手机便签下载
  20. 格创东智亮相高端制造业CIO上海论坛,助推制造业智慧建设

热门文章

  1. Quartus II调用modelsim ALTEA 的软件使用及问题
  2. [图解]管理九段的新排列
  3. SSAS : 如何编写自定义挖掘算法
  4. 服务器中文档存储在哪,云服务器存储在哪
  5. python科研计价_科研速递 | 花费15年众望所归!NumPy论文终登上Nature!
  6. vscode插件之Vetur
  7. html引入html include_PostgreSQL引入插件EXTENSION的常用方法
  8. 清华同方计算机教程,清华同方电脑u盘重装系统win10教程
  9. mongodb 良贴
  10. 纯CSS3渐变色板配色代码