第12章广义变量.pdfVIP

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
  4. 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
  5. 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们
  6. 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
  7. 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
第12章广义变量

第 12 章 ⼴义变量 第 12 章 ⼴义变量 第 8 章曾提到,宏的长处之⼀是其变换参数的能⼒。setf 就是这类宏中的⼀员。本 章将着重分 setf 的内涵,然后以⼏个宏为例,它们将建⽴在 setf 的基础之上。 要在 setf 上编写正确⽆误的宏并⾮易事,其难度让⼈咋⾆。为了介绍这个主题,第 ⼀节会先给出⼀个有点⼩问题的简单例⼦。接下来的⼩节将解释该宏的错误之处,然 后展⽰如何改正它。第三和第四节会介绍⼀些基于 setf 的实⽤⼯具的例⼦,⽽最后 ⼀节则会说明如何定义你⾃⼰的 setf 逆变换。 12.1 概念 内置宏 setf 是 setq 的推⼴形式。setf 的第⼀个参数可以是个函数调⽤⽽⾮简单 的变量: (setq lst (a b c)) (A B C) (setf (car lst) 480) 480 lst (480 B C) ⼀般⽽⾔,(setf x y) 可以理解成 务必让 x 的求值结果为 y。作为⼀个 宏,setf 得以深⼊到参数内部,弄清需要做哪些⼯作,才能满⾜这个要求。如果第 ⼀个参数(在宏展开以后) 是个符号,那么setf 就只会展开成 setq 。但如果第⼀个参 数是个查询语句,那么 setf 则会展开到对应的断⾔上。由于第⼆个参数是常量,所 以前⾯的例⼦可以展开成: (progn (rplaca lst 480) 480) 这种从查询到断⾔的变换被称为逆变换。Common Lisp 中所有最常⽤的访问函数都有 预定义的逆,包括 car、cdr、nth、aref、get、gethash,以及那些 由 defstruct 创建的访问函数。( 完整的名单见 CLTL2 的第 125 页。) 能充当 setf 第⼀个参数的表达式被称为⼴义变量。⼴义变量已经成为了⼀种强有⼒ 的抽象机制。宏调⽤和⼴义变量的相似之处在于:⼀个宏调⽤,只要能展开成可逆引 ⽤,那么其本⾝就⼀定是可逆的。 当我们也加⼊这个⾏列,基于 setf 编写⾃⼰的宏时,这种组合可以产⽣显⽽易见更 清爽的程序。我们可以在 setf 上⾯定义的宏有很多,其中⼀个是 toggle: 【注1】 (defmacro toggle (ob ) (setf ,ob (not ,ob ))) 它可以反转⼀个⼴义变量的值: (let ((lst (a b c))) (toggle (car lst)) lst) (NIL B C) 现在考虑下⾯的应⽤。假设有个⼈,他可能是个肥皂剧作者、精⼒充沛的好事者,或 是居委会⼤妈,想要维护⼀个数据库。其中记录着⼩镇上所有居民之间的种种恩怨情 仇。在数据库⾥的表⾥,其中有⼀张便是⽤来保存朋友关系的: (defvar *friends* (make-hash-table)) 这个哈希表的表项本⾝也是哈希表,其中,潜在的朋友被映射到 t 或者 nil : (setf (gethash mary *friends*) (make-hash-table)) 为了使 John 成为 Mary 的朋友,我们可以说: (setf (gethash ohn (gethash mary *friends*)) t) 这个镇被分为两派。正如帮派的传统,每个⼈都声称 凡⼈⾮友即敌 ,所以镇上所有 ⼈都被迫加⼊⼀⽅或者另⼀⽅。这样当某⼈转变⽴场时,他所有的朋友都变成敌⼈, ⽽所有的敌⼈则变成朋友。 如果只⽤内置的操作符来切换 x 和 y 的敌友关系,我们必须这样说: (setf (gethash x (gethash y *friends*)) (not (gethash x (gethash y *friends*)))) 尽管去掉 setf 后要简单许多,这个表达式还是相当复杂。倘若我们为数据库定义了 ⼀个访问宏,如下: (defmacro friend-of (p q) (gethash ,p (gethash ,q *friends*))) 那么在这个宏和 toggle 的协助下,我们就得以更⽅便地修改数据库的数据。前⾯那 个更新数据库的语句可以简化成: (toggle (friend-of x y)) ⼴义变量就像是美味的健康⾷品。它们能让你的程序良好地模块化,同时变得更为优 雅。如果你给出宏或者可逆函数,⽤来访问你的数据结构,那么其他模块就可以使 ⽤ setf 来修改你的数据结构⽽⽆需了解其内部细节。 12.2 多重求值问题 上⼀节曾警告

文档评论(0)

ctuorn0371 + 关注
实名认证
文档贡献者

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

1亿VIP精品文档

相关文档