(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的描述app
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-1 whose elements are L1i for i < n-1 followed by L2j for j < m). ``The list (1 2 (3 4 5)) is a spreadable argument list designator for the list (1 2 3 4 5).''
发现第二个apply和日常的调用不一样在于,此次有2个function,1个list.atom
日常调用apply:spa
(apply #'(lambda (&rest args) args) '(a b c))
日常调用函数:rest
((lambda (&rest args) args) 'd '(a b c))
&rest超过一个list的调用:code
(apply #'(lambda (&rest args) args) 'd '(a b c))
在机器上运行上面3个调用,会发现第三个调用至关于对&rest中的参数作了一次拆解,最后一个列表又恰好是传入参数,曾被&rest包装过一次,在这里利用apply的这个特性,作了拆解,天然没有造成无限递归.blog
结论:一个函数使用由&rest传递进来的参数调用一个其余函数时,用apply调用那个函数,一次包装一次拆解恰好抵消.递归