(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調用那個函數,一次包裝一次拆解恰好抵消.遞歸