网站大量收购独家精品文档,联系QQ:2885784924
  1. 1、本文档共21页,可阅读全部内容。
  2. 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
  3. 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  4. 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
测系大修第7章宏

第 7 章 宏 第 7 章 宏 Lisp 中,宏的特性让你能⽤变换的⽅式定义操作符。宏定义在本质上,是能⽣成 Lisp 代码的函数 -- 个能写程序的程序。这 ⼩⼩开端引发了巨⼤的可能性,同时也伴随 着难以预料的风险。 第 7-10 章将带你⾛⼊宏的世界。本章会解释宏如何⼯作,介绍编写和调试它们的技 术,然后分析 些宏风格中存在的问题。 7.1 宏是如何⼯作的 由于我们可以调⽤宏并得到它的返回值,因此宏往往被⼈们和函数联系在 起。宏定 义有时和函数定义相似,⽽且不严谨地说,被⼈们称为 内置函数 的 do 其实就是 个宏。但如果把两者过于混为 谈,就会造成很多困惑。宏和常规函数的⼯作⽅式截 然不同,并且只有知道宏为何不同,以及怎样不同, 才是⽤好它们的关键。 个函数 只产⽣结果,⽽宏却产⽣表达式。当它被求值时,才会产⽣结果。 要⼊门,最好的办法就是直接看个例⼦。假设我们想要写 个宏 nil!,它把实参设 置为 nil。让(nil! x) 和 (setq x nil) 的效果 样。我们完成这个功能的⽅法 是:把 nil! 定义成宏,让它来把前 种形式的实例变成后 种形式的实例: (defmacro nil! (var) (list setq var nil)) NIL! ⽤汉语转述的话,这个定义相当于告诉 Lisp : ⽆论何时,只要看到形如 (nil!) 的 表达式,请在求值之前先把它转化成 (setq nil) 的形式。 宏产⽣的表达式将在调⽤宏的位置求值。宏调⽤是 个列表,列表的第 个元素是宏 的名称。当我们把宏调⽤ (nil! x) 输⼊到 toplevel 的时候发⽣了什么? Lisp ⾸先 会发觉 nil! 是个宏的名字,然后: 1. 按照上述定义的要求构造表达式,接着, 2. 在调⽤宏的地⽅求值该表达式。 构造新表达式的那 步被称为宏展开 (macro expansion )。Lisp 查找 nil! 的定义, 其定义展⽰了如何为宏调⽤构建 个即将取代它的表达式。和函数 样,nil! 的定 义也应⽤到了宏调⽤传给它的表达式参数上。 它返回 个三元素列表,这三个元素分别是: setq、作为参数传递给宏的那个表达 式,以及 nil。在本例中,nil! 的参数是 x ,宏展开式是 (setq x nil)。 宏展开之后是第⼆步:求值 (evaluation )。Lisp 求值宏展开式 (setq x nil) 时就 好像是你原本就写在那⼉的 样。求值并不总是⽴即发⽣在展开之后,不过 在 toplevel 下的确是这样的。 个发⽣在函数定义⾥的宏调⽤将在函数编译时展 开,但展开式 或者说它产⽣的对象代码, 要等到函数被调⽤时才会求值。 如果把宏的展开和求值分清楚,你遇到的和宏有关的困难,或许有很多就能避免。当 编写宏的时候,要清楚哪些操作是在宏展开期进⾏的,⽽哪些操作是在求值期进⾏ 的,通常,这两步操作的对象截然不同。宏展开步骤处理的是表达式,⽽求值步骤处 理的则是它们的值。 有些宏的展开过程⽐ nil! 的情况更复杂。nil! 的展开式只是调⽤了 下内置 的 special form,但往往 个宏的展开式可能会是另 个宏调⽤,就好像是 层 套 层的俄罗斯套娃。在这种情况下,宏展开就会继续抽丝剥茧直到获得 个没有宏 的表达式。这 步骤中可以经过任意多次的展开操作, 直到最终停下来。 尽管有许多语⾔也提供了某种形式的宏,但 Lisp 宏却格外强⼤。在编译 Lisp ⽂件 时,解析器先读取源代码,然后将其输出送给编译器。这⾥有个天才的⼿笔:解析器 的输出由 Lisp 对象的列表组成。通过使⽤宏,我们可以操作这种处于解析器和编译器 之间的中间状态的程序。如果必要的话,这些操作可以⽆所不包。 个⽣成展开式的 宏拥有 Lisp 的全部威⼒,可任其驱驰。事实上,宏是货真价实的 Lisp 函数 那种能返 回表达式的函数。虽然 nil! 的定义中只是调⽤了 下 list ,但其他宏⾥可能会驱 动整个⼦程序来⽣成其展开式。 有能⼒改变编译器所看到的东西,差不多等同于能够对代码进⾏重写。所以我们就可 以为语⾔增加任何构造,只要⽤变换的⽅法把它定义成已有的构造。 7.2 反引⽤ (backquote ) 反引⽤ (backquote )是引⽤ (quote )的特别版本,它可以⽤来创建 Lisp 表达式的模 板。反引⽤最常见的⽤途之 是⽤在宏定义⾥。 反引⽤

文档评论(0)

aena45 + 关注
实名认证
内容提供者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档