2017-02-14 29 views
3

我是通用lisp的新手,當我在函數參數聲明中看到&rest時,我認爲它與ruby中的*args類似。我開始寫一個函數sumit來做和+一樣的功能。如何處理共同lisp的`&rest`參數

(defun sumit (&rest args) 
    (if (null args) 
     0 
     (+ (car args) (sumit (cdr args))))) 

但是當我調用(sumit 1 2 3)它得到分段錯誤,遞歸永遠不會結束。 (sumit)雖然工作。

所以我的懷疑是(null args)的一部分,但是在改變(eql nil args)之類的東西之後不起作用。

那麼什麼是正確的方法來分解&rest參數?什麼是檢查nil的正確方法?

+3

'SUMIT'將可變數量的數字作爲參數,但是在'(sumit(cdr args))'中,您使用單個列表參數調用它,而不是數字。你需要使用'(apply#'sumit(cdr args))'代替。 – jkiiski

+0

@jkiiski ohhh,沒錯!謝謝!順便說一句,有什麼辦法可以將列表擴展爲多個參數,而不使用'apply'嗎? – delta

+0

@delta:no,use APPLY –

回答

3

(sumit (cdr args))在單個參數 - 列表上調用sumit。 您需要使用apply

(defun sumit (&rest args) 
    (if args 
     (+ (car args) (apply #'sumit (cdr args))) 
     0)) 

注:

  1. 此實現不是尾遞歸(而ANSI CL不要求尾部調用優化,許多實現它提供) 。
  2. 看看call-arguments-limitlambda-parameters-limit
  3. 綜上所述列表中的一個元素可以使用(apply #'+ list-of-numbers), 但是,由於上述兩個變量, (reduce #'+ list-of-numbers) 是一個更好的方法。
+0

關於註釋1,Common Lisp無論如何都不保證尾遞歸。 – acelent

+1

@acelent:謝謝,是的,我知道,請參閱編輯。 – sds