网站大量收购独家精品文档,联系QQ:2885784924

第 5 篇 函数作为返回值.pdf

  1. 1、本文档共13页,可阅读全部内容。
  2. 2、有哪些信誉好的足球投注网站(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
  3. 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  4. 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
第 5 章 函数作为返回值 第 5 章 函数作为返回值 上⼀章展⽰了 Lisp 把函数作为参数传递 的能⼒,它开阔了我们进⾏抽象的思路。我 们对函数能 的事情越多,就越能充分利⽤这些思想⽅法。如果能定义⼀种函数,让 它产⽣并返回新的函数,那就可以成倍放⼤那些以函数作为参数的实⽤⼯具的威⼒。 这⼀章要介绍的实⽤⼯具就被⽤来操作函数。要是把它们中的多数写成宏,让这些宏 来操纵表达式会显得更⾃然⼀些,⾄少在 Common Lisp ⾥是这样的。在第 15 章会把 ⼀层宏加到这些操作符之上。不管怎样,就算最终这些函数仅仅被宏调⽤,了解哪 些⼯作能由函数来完成 这⼀点也⾄关重要。 5.1 Common Lisp 的演化 Common Lisp 最初提供了⼏组互补的函数。remove-if 和 remove-if-not 就是这样的⼀ 对。倘若 pred 是⼀个参数的谓词,那么: (remove-if-not #pred lst) 就和下⾯语句等价: (remove-if #(lambda (x) (not (pred x))) lst) 只要把其中⼀个语句的函数参数换⼀下,就能获得和另⼀语句完全相同的效果。既然 如此,为什么要同时保留两个语句呢?C2 ⾥提供了⼀个新的函数,它就是为了解 决上述问题⽽⽣的: complement 需要⼀个谓词 p 作为参数,它返回⼀个函数,这个 函数的返回值总是和谓词得到的返回值相反。当p 返回真的时候, 它的补 (complement ) 就返回假,反之亦然。现在我们可以把: (remove-if-not #pred lst) 换成与之等价的: (remove-if (complement #pred) lst) 有了 complement ,就没有什么理由再⽤那些-if-not 函数了。 事实上, 2 (39 1 页) 提到那些函数现在已经淘汰了。如果它们还在 Common Lisp ⾥⾯,那只是为了 照顾兼容性。 新的complement 操作符仅是冰⼭⼀⾓: 即⼀种返回函数的函数。这在很早就是 Scheme 的习惯⽤法中重要的⼀部分了。Scheme 是Lisp 家族中第⼀个能把函数作为词 法闭包 (lexicalclosures ) 的语⾔,⽽且正是这⼀点让函数作为返回值 变得有趣起 来。 这并不意味着我们不能在动态作⽤域的Lisp ⾥返回函数。下⾯的函数能同时在动态作 ⽤域和词法作⽤域下⼯作: (defun joiner (obj) (typecase obj (cons #append) (number #+))) 上⾯的函数以⼀个对象作为参数,按照参数的类型,返回相应的函数把这种对象累加 起来。通过它,我们可以定义⼀个多态 (pol morphic ) 的join 函数,这个函数可以⽤ 于⼀组数字或者列表。 remove-if-not 可能是个例外,它⽐remove-if 更常⽤⼀些。 (defun join (rest args) (apply (joiner (car args)) args)) 然⽽,只能返回⼀个常量函数 是动态作⽤域的限制之⼀。由于这个限制, 我们所⽆ 法 到 (或者说⽆法 得好) 的是在运⾏期构造函数: 尽管joiner 可以返回两个函数 之⼀,但是这两个选择是事先给定的,⽆法变更。 在第12页,我们见到了另⼀个⽤来返回函数的函数,它就依赖于词法作⽤域: (defun make-adder (n) #(lambda (x) (+ x n))) 调⽤make-adder 后,会得到⼀个闭包,闭包的⾏为视当初传⼊函数的参数值⽽定: (set add3 (make-adder 3)) #Interpreted-Function BF1356 (funcall add3 2) 5 在词法作⽤域下,我们不再仅仅是从⼀组预先确定的函数中选⼀个,⽽是在运⾏时创 造新的闭包。但要是动态作⽤域的话,这个技术就⾏不通了。 如果想⼀想complement 是怎么写的,也可以推知它返回的必定也是⼀个闭包: (defun complement (fn) #(lambda (rest args) (not (apply fn args)))) complement 返回的函数使⽤了之前调⽤complement 时传⼊的参数值fn 。因此, compleme

文档评论(0)

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

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

1亿VIP精品文档

相关文档