- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
第 16 章 定义宏的宏
第 16 章 定义宏的宏
第 16 章 定义宏的宏
代码中的模式通常预⽰着需要新的抽象。这⼀规则对于宏代码本⾝也⼀样适⽤。如
⼏个宏的定义在形式上⽐较相似,我们就可能写⼀个编写宏的宏来产⽣它们。本章展
⽰三个宏定义宏的例⼦:⼀个⽤来定义缩略语,另⼀个⽤来定义访问宏,第三个则⽤
来定义在 14 .1 节中介绍的那种指代宏。
16.1 缩略语
宏最简单的⽤法就是作为缩略语。⼀些 Common Lisp 操作符的名字相当之长。它们中
最典型的 (尽管不是最长的) 是 destructuring-bind ,长达 18 个字符。Steele 原则(4 .3
节) 的⼀个直接推论是,常⽤的操作符应该取个简短的名字。(我们认为加法的成本较
低,部分原因是由于我们只要⽤⼀个字符 + 就可以表⽰它。) 内置的 destructuring-
bind 宏引⼊了⼀个新的抽象层,但它在简洁上作出的贡献被它的长名字抹杀了:
(let ((a (car x)) (b (cdr x))) ...)
(destructuring-bind (a . b) x ...)
和打印出来的⽂本相似,程序在每⾏的字符数不超过 7 的时候,是最容易阅读的。
当单个名字的长度达到这个长度的四分之⼀时,我们就开始觉得不便了。
幸运的是,在像 Lisp 这样的语⾔⾥你完全没有必要逆来顺受设计者的每个决定。只要
定义了:
(defmacro dbind (rest args)
(destructuring-bind ,@args))
你就再也不没必要⽤那个长长的名字了。对于名字更长也更常⽤的multiple-value-bind
也是⼀样的道理。
(defmacro mvbind (rest args)
(multiple-value-bind ,@args))
注意到 dbind 和 mvbind 的定义是何等的相似。确实,使⽤这种 rest 和逗号-at 的惯⽤
法,就已经能为任意⼀个函数 【注1】、宏,或者 special form 定义其缩略语了。
既然我们可以让⼀个宏帮我们代劳,为什么还⽼是照着 mvbind 的模样写出⼀个又⼀
个的定义呢?
为了定义⼀个定义宏的宏,我们通常会要⽤到嵌套的反引⽤。嵌套反引⽤的难以理解
是出了名的。尽管最终我们会对那些常见的情况了如指掌,但你不能指望随便挑⼀个
反引⽤表达式,都能看⼀眼,就能⽴即说出它可以产⽣什么。这不能归罪于 Lisp 。就
像⼀个复杂的积分,没⼈能看⼀眼就得出积分的结 ,但是我们不能因为这个就把问
题归咎于积分的表⽰⽅法。道理是⼀样的。难点在于问题本⾝,⽽⾮表⽰问题的⽅
法。
尽管如此,正如在我们在做积分的时候,我们同样也可以把对反引⽤的分析拆成多个
⼩⼀些的步骤,让每⼀步都可以很容易地完成。假设我们想要写⼀个 abbrev 宏,它允
许我们仅⽤:
(abbrev mvbind multiple-value-bind)
[⽰例代码 16.1] ⾃动定义缩略语
(defmacro abbrev (short long)
(defmacro ,short (rest args)
(,,long ,@args)))
(defmacro abbrevs (rest names)
(progn
,@(mapcar #(lambda (pair)
(abbrev ,@pair))
(group names 2))))
来定义 mvbind 。[⽰例代码 16.1] 给出了⼀个这个宏的定义。它是怎样写出来的呢?
这个宏的定义可以从⼀个⽰例展开式开始。⼀个展开式是:
(defmacro mvbind (rest args)
(multiple-value-bind ,@args))
如 我们把 multiple-value-bind 从反引⽤⾥拉出来的话,就会让推导变得更容易些,
因为我们知道它将成为最终要得到的那个宏的参数。这样就得到了等价的定义:
(defmacro mvbind (rest args)
(let ((name multiple-value-bind))
(,name ,@args)))
现在我们将这个展开式转化成⼀个模板。我们先把反引⽤放在前⾯,然后把可变的表
达式替换成变量。
(defmacro ,short (rest args)
(let ((name ,long))
文档评论(0)