2010-02-18 38 views
3

我最近寫更多的Lisp代碼。特別是需要一些數據的遞歸函數,並構建一個結果數據結構。有時候,除了用戶提供的數據之外,似乎還需要將兩個或三個信息傳遞給函數的下一個調用。讓我們打電話給這些累加器。什麼是包括參數,如功能累加器最佳做法?

組織這些接口到我的代碼的最佳方式是什麼?

目前,我做這樣的事情:

(defun foo (user1 user2 &optional acc1 acc2 acc3) 
    ;; do something 
    (foo user1 user2 (cons x acc1) (cons y acc2) (cons z acc3))) 

這個工程,我想它想的,但我很擔心,因爲我並不真的需要出示&可選參數編​​程。

3種方法我有點考慮:

  • 有用戶被鼓勵使用立即調用擴展definiton的包裝功能。

  • 在內部使用labels內部的一個函數,其簽名是簡潔的。

  • 剛開始使用循環和變量。不過,我寧願不要,因爲我想真正包裹我的頭遞歸。

謝謝你們!

回答

4

如果你想編寫慣用的Common Lisp,我會推薦迭代的循環和變量。遞歸很酷,但它只是Common Lisper的許多工具之一。此外,Common Lisp規範不保證tail-call消除。

這就是說,我會建議labels方法,如果你有一個結構,例如一棵樹,這是不可避免的遞歸,你不能獲得尾調用反正。可選參數讓您的實現細節泄漏給調用者。

+0

謝謝。我有一些處理樹木的功能,所以我將它們轉換爲使用「標籤」。另一組函數只在列表中運行,所以我利用這個機會熟悉'loop'。 – 2010-02-19 20:12:07

2

我認爲,從用戶那裏屏蔽實施細節的衝動是明智之舉。我不知道普通的lisp,但是在Scheme中,你可以通過在公共函數的詞法範圍中定義輔助函數來實現它。

(define (fibonacci n) 
    (let fib-accum ((a 0) 
        (b 1) 
        (n n)) 
    (if (< n 1) 
     a 
     (fib-accum b (+ a b) (- n 1))))) 

let表達式定義了一個函數,並將其綁定到該設內只有可見的名稱,然後調用函數。

+1

是的,我想的Common Lisp的'labels'相當於計劃的'在這種情況下let'漂亮多了。 – Ken 2010-02-18 16:19:10

0

我用你提到的選項。一切都有其優點,所以歸結爲個人偏好。

我在使用任何我認爲合適的到來。如果我想離開&optional蓄電池在API中可能有意義的用戶,我把它留在。例如,在reduce樣的功能,蓄能器可以由用戶提供一個初始值使用。否則,我經常會將它重寫爲loop,doiter(來自迭代庫)的形式,如果有意義的話。有時候,labels幫手也被使用。

相關問題