《On Lisp》第四章第三节图4.6中的rmapcar函数中展现的apply陷阱
(defun rmapcar (fn &rest args)
(if (some #'atom args)
(apply fn args)
(apply #'mapcar
#'(lambda (&rest args)
(apply #'rmapcar fn args))
args)))
这段代码第一眼看上去,怎么都像无限递归,不断的用&rest对参数做list,然后用mapcar做car,但是这段代码又是确确实实能运行的.仔细分析以后,可以肯定哪个函数的调用对参数多做了一次类似car的拆解.
当看到apply函数时,想起《Ansi Common Lisp》中对apply的描述
apply接受一个函数和任意数量的参数,但是最后一个参数必须是一个列表
Syntax:
apply function &rest args+ => result*
虽然很多函数都有&rest参数,由于&rest会自动把不定的参数组成一个列表,这个函数的说明就略显突兀了,于是查看了参数说明.
args---a spreadable argument list designator.
spreadable argument list designator n. a designator for a list of objects; that is, an object that denotes a list and that is a non-null list L1 of length n, whose last element is a list L2 of length m (denoting a list L3 of length m+n- whose elements are L1i for i < n- followed by L2j for j < m). ``The list ( ( )) is a spreadable argument list designator for the list ( ).''
发现第二个apply和平常的调用不同在于,这次有2个function,1个list.
平常调用apply:
(apply #'(lambda (&rest args) args) '(a b c))
平常调用函数:
((lambda (&rest args) args) 'd '(a b c))
&rest超过一个list的调用:
(apply #'(lambda (&rest args) args) 'd '(a b c))
在机器上运行上面3个调用,会发现第三个调用相当于对&rest中的参数做了一次拆解,最后一个列表又刚好是传入参数,曾被&rest包装过一次,在这里利用apply的这个特性,做了拆解,自然没有形成无限递归.
结论:一个函数使用由&rest传递进来的参数调用一个其他函数时,用apply调用那个函数,一次包装一次拆解刚好抵消.
《On Lisp》第四章第三节图4.6中的rmapcar函数中展现的apply陷阱的更多相关文章
- 《On Lisp》第四章第三节图4.3中的prune函数fix
这个函数作者的原意是删除表中test位真的部分,并且表按原样返回. 作者给出的的测试用例如下: (prune #'evenp '(1 2 (3 (4 5) 6) 7 8 (9))) 返回结果是: (1 ...
- 微信小程序教学第四章第三节(含视频):小程序中级实战教程:详情-功能完善
详情 - 功能完善 本文配套视频地址: 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 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (21) -----第四章 ASP.NET MVC中使用实体框架之在页面中创建查询和使用ASP.NET URL路由过虑
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 4.2. 构建一个搜索查询 搜索数据是几乎所有应用的一个基本功能.它一般是动态的,因 ...
- C# Language Specification 5.0 (翻译)第四章 类型
C# 语言的类型分为两大类:值类型(value type)和引用类型(reference type),而它们又都同时具有至少一个类型形参的泛型类型(generic type).类型形参(type pa ...
- 第四章 使用Docker镜像和仓库(二)
第四章 使用Docker镜像和仓库(二) 回顾: 开始学习之前,我先pull下来ubuntu和fedora镜像 [#9#cloudsoar@cloudsoar-virtual-machine ~]$s ...
- JavaScript高级程序设计:第十四章
第十四章 一.表单的基础知识 在HTML中,表单是由<form>元素来表示的,而在javascript中,表单对应的则是HTMLFormElement类型.HTMLFormElement继 ...
随机推荐
- oracle之trunc与round
round(x[,y]) 功能:返回四舍五入后的值 参数:x,y,数字型表达式,如果y不为整数则截取y整数部分,如果y>0则四舍五入为y位小数,如果y小于0则四舍五入到小数点向左第y位. 返回: ...
- 【转】基于第一个PhoneGap(cordova)的应用详解
PhoneGap是一套能让你使用HTML5轻松调用本地API接口和发布应用到商店的应用开发平台.官方说有低成本,低开发周期,轻量化等优点,这些咱暂时也没法证明,略过不表.但是有一条跨平台,却是很明显的 ...
- Allegro 快捷键设置
一.快捷键设置 Allegro可以通过修改env文件来设置快捷键,这对从其它软件如AD或PADS迁移过来的用户来说,可以沿用以前的操作习惯,还是很有意义的. Allegro的变量文件一共有2个:一个是 ...
- spark1.3编译过程中遇到的一个坑
在编译spark1.3.0时: export MAVEN_OPTS="-Xmx2g -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=512m&q ...
- fw: webdriver 那些坑
http://www.cnblogs.com/huang0925/p/3384596.html 使用WebDriver遇到的那些坑 在做web项目的自动化端到端测试时主要使用的是Selenium ...
- Android的各种Drawable 讲解 大全
Android把可绘制的对象抽象为Drawable,不同的图形图像资源就代表着不同的drawable类型.Android FrameWork提供了一些具体的Drawable实现,通常在代码中都不会直接 ...
- GCC的gcc和g++区别
看的Linux公社的一篇文章,觉得不错,内容复制过来了. 其实在这之前,我一直以为gcc和g++是一个东西,只是有两个不同的名字而已,今天在linux下编译一个c代码时出现了错误才找了一下gcc和g+ ...
- java.lang.classnotfoundexception org.json.jsonexception
java.lang.classnotfoundexception org.json.jsonexception 解决方法 http://www.java2s.com/Code/Jar/j/Downlo ...
- ARToolKit for Unity环境搭建(初步搭建成功)
最近一段时间才开始学习使用Unity3d,AR的学习使用中,先后使用了metaio SDK.vuforia SDK,但由于这两个都属于收费的,今天开始尝试使用ARToolKit.先将ARToolKit ...
- 使用es6的set和map实现数组去重复
var set = new Set();var arr = [1, 2, 3, 3, 2, 1];arr.map(val => set.add(val));// arr.map(function ...