《On Lisp》第四章第三节图4.3中的prune函数fix
这个函数作者的原意是删除表中test位真的部分,并且表按原样返回.
作者给出的的测试用例如下:
(prune #'evenp '(1 2 (3 (4 5) 6) 7 8 (9)))
返回结果是:
(1 (3 (5)) 7 (9))
这里的(9)应为刚好被evenp判断为假,所以正常包含在列表当中了,可是当有类似(9)这样的单元素列表包含在内的特殊情况就被作者忽略了,我偶然输入了如下测试用例,起初只是为了观察嵌套列表的层数是否因递归而减少.
(prune #'evenp '((((1 2) 3 4)) 5 (6) (7) (((8 9)))))
得到如下的结果:
((((1) 3)) 5 NIL (7) (((9))))
嵌套层数未变,可是却多出了一个nil,仔细观察代码,会发现这个nil必然是多余的,如果不是多余的,这个函数可以用很容易理解的递归完成.于是下面就想着自己完善这个实用工具.
(defun prune (test tree)
(labels ((rec (tree acc)
(cond ((null tree) (nreverse acc)) ;4
((consp (car tree))
(rec (cdr tree)
(cons (rec (car tree) nil) acc))) ;2
(t (rec (cdr tree)
(if (funcall test (car tree))
acc ;3
(cons (car tree) acc)))))))
(rec tree nil))) ;1
首先,肯定是多了个nil元素被添加到列表中,所以我们要寻找这个nil的来源.
先看4,这个是递归函数出口,nil完全不可能来自这里,而1是入口,这里的nil明显是迭代列表.
那剩下来只有2和3了.仔细观察,发现进入t分支的时,只要是由于分支2的调用,acc便是nil,只有在3分支的下一个元素是在一个层级上,才能迭代这个层级的表项.也就是说,真正产生表项的,是分支3.既然找到了nil的源头,那问题就简单了,只要分支3返回nil,就忽略掉.
(defun prune (test tree)
(labels ((rec (tree acc)
(cond ((null tree) (nreverse acc))
((consp (car tree))
(let ((ret (rec (car tree) nil))) ;fixed
(if ret
(rec (cdr tree) (cons ret acc))
(rec (cdr tree) acc))))
(t (rec (cdr tree)
(if (funcall test (car tree))
acc
(cons (car tree) acc)))))))
(rec tree nil)))
《On Lisp》第四章第三节图4.3中的prune函数fix的更多相关文章
- 《On Lisp》第四章第三节图4.6中的rmapcar函数中展现的apply陷阱
(defun rmapcar (fn &rest args) (if (some #'atom args) (apply fn args) (apply #'mapcar #'(lambda ...
- 微信小程序教学第四章第三节(含视频):小程序中级实战教程:详情-功能完善
详情 - 功能完善 本文配套视频地址: https://v.qq.com/x/page/f0555nfdi14.html 开始前请把 ch4-3 分支中的 code/ 目录导入微信开发工具 这一节中, ...
- jQuery_第四章_思维图
---------------------------------------------------------------------------------------------------- ...
- 啊哈算法第四章第三节 层层递进-广度优先搜索 java实现
package corejava; public class FourThree { static int [][]a=new int[50][50]; static int [][]b=new in ...
- 剑指offer-第四章解决面试题的思路(包含min函数的栈)
题目:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数,在该栈中,调用min,push及pop的时间复杂度都是O(1) 思路:定义两个栈分别为dataStack和minStack ...
- C# Language Specification 5.0 (翻译)第四章 类型
C# 语言的类型分为两大类:值类型(value type)和引用类型(reference type),而它们又都同时具有至少一个类型形参的泛型类型(generic type).类型形参(type pa ...
- 第四章:重构代码[学习Android Studio汉化教程]
第四章 Refactoring Code The solutions you develop in Android Studio will not always follow a straight p ...
- 【软件构造】第三章第三节 抽象数据型(ADT)
第三章第三节 抽象数据型(ADT) 3-1节研究了“数据类型”及其特性 ; 3-2节研究了方法和操作的“规约”及其特性:在本节中,我们将数据和操作复合起来,构成ADT,学习ADT的核心特征,以及如何设 ...
- 《Django By Example》第四章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:祝大家新年快乐,这次带来<D ...
随机推荐
- JVM实用参数(七)CMS收集器
HotSpot JVM的并发标记清理收集器(CMS收集器)的主要目标就是:低应用停顿时间.该目标对于大多数交互式应用很重要,比如web应用.在我们看一下有关JVM的参数之前,让我们简要回顾CMS收集器 ...
- Android Studio项目目录结构介绍
在Android Studio中,提供了以下几种项目结构类型 我们一般常用的有以下两种结构: Project 结构类型 app/build/ app模块build编译输出的目录 app/build.g ...
- Java基础语法目录
一.Java相关科普知识1.Java的发展历程2.Java的发展方向3.Java的体系特性二.Java第一个程序1.JavaJDK的安装与环境的配置2.记事本开发Java程序的注意事项与常见问题3.J ...
- fdisk -c 0 350 1000 300命令
在Linux中有一个fdisk的分区命令,在对开发板的nand或者emmc分区也会用到这个命令, fdisk -c 这里0 350 1000 300分别代表: 每个扇区大小为0,一共350个柱面,起始 ...
- Easyui datebox 限制时间选择范围
Require Date: <input class="easyui-datebox" data-options="formatter:myformatter,pa ...
- Jsp与servlet本质上的区别
1.jsp经编译后就变成了Servlet.(JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器将JSP的代码编译成JVM能够识别的java类)2.jsp更擅长 ...
- 利用sp_addlinkedserver实现远程数据库链接
--查看当前链接情况: select * from sys.servers; --使用 sp_helpserver 来显示可用的服务器 Exec sp_helpserver --删除已经存在的某个链接 ...
- 转载-------makefile 使用总结
转载自:http://www.cnblogs.com/wang_yb/p/3990952.html 1. Makefile 简介 Makefile 是和 make 命令一起配合使用的. 很多大型项目的 ...
- javascript的地基
有了良好的基础,才能在其上创造有价值的东西. 回顾一下以往自己javascript应用的开发经历,似乎很少去思考和总结js的运行机制.现在我就来整理整理 1. 以<编译原理>的一段话开头: ...
- node.js搭建简单的websocket
1.首先在官网http://www.nodejs.org/下载NODE.JS 2.打开命令行CMD,进入NODEJS\node_modules\的目录,输入npm install socket.io ...