Programming Clojure学习笔记——宏

7.2 编写控制流宏
实现unless功能,与if相反,条件不成立时执行unless后代码。
先编写函数来实现:
user=> (defn unless [expr form] (if expr nil form))
验证一下,当表达式expr为false时正确执行
user=> (unless false (println "this should print"))
this should print
但是当expr为true时,也会执行unless后的代码
user=> (unless true (println "this should not print"))
this should not print
原因分析:
Clojure在将参数传递给函数之前,先计算所有参数值,因此就在判断前就执行了println函数。

宏可以解决这个问题,它们不会立即计算参数值。当Clojure遇到宏时,它分两步进行处理:
(1) 首先展开(或者说是执行)宏,将结果替换到原程序中,这个阶段被称为宏展开期
(2) 然后进行正常的编译,这个阶段被称为编译期

宏的定义通过defmacro关键字:
(defmacro name doc-string? attr-map? [params*] body)

使用宏实现unless功能
user=> (defmacro unless [expr form] (list 'if expr nil form))
验证一下
user=> (unless false (println "this should print"))
this should print
说明:执行过程中,Clojure会自动将unless形式展开为:
(if false nil (println "this should print"))
user=> (unless true (println "this should not print"))
nil
完全实现了unless功能。

特殊形式,设计模式和宏
Clojure在代码上没有特殊语法,它的代码有数据结构组成,也就是说数据即代码。而Java中有很多特殊形式,如在Java中实现unless功能,我们只能通过下面的语句来模拟:
if (!something) ...

Java中将一些常用的解决办法称为设计模式,然而设计模式不是一个完成的设计不能直接转换为代码。而Clojure的宏提供了一个间接的层可以自动完成重复出现模式的公共部分,与代码即数据的特性一起,使得你可以重写你的语言从而在运行中封装模式。

展开宏
函数macroexpand-1将显示宏展开的结果:
(macroexpand-1 form),如:
user=> (macroexpand-1 '(unless false (println "this should print")))
(if false nil (println "this should print"))

有时宏展开后还是宏,此时Clojure将继续展开直到只有正常代码为止。使用macroexpand函数可以查看递归展开结果:
(macroexpand form),如:
user=> (macroexpand '(.. arm getHand getFinger))
(. (. arm getHand) getFinger)

when和when-not
(when test & body)
(when-not test & body)
when-not宏的定义为:
(defmacro when-not [test & body]
&nbps;   (list 'if test nil (cons 'do body)))
示例:
user=> (when-not false (println "this") (println "and also this"))
this
and also this
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值