2013-10-17 180 views
6

我們發現這個函數生成器可以在P.Graham的「ANSI Common Lisp」(第110頁)中實現合成。 參數是n> 0引用的函數名稱。我不完全理解它,所以我會在這裏引用的代碼,並指定我的問題,它的下面:(撰寫)在Common Lisp

(defun compose (&rest fns) 
    (destructuring-bind (fn1 . rest) (reverse fns) 
    #'(lambda (&rest args) 
     (reduce #'(lambda (v f) (funcall f v)) 
       rest 
       :initial-value (apply fn1 args))))) 

參數列表組成反轉,解壓後,其(現第一)元素綁定到「FN1 '和其餘的'休息'。 最外層的lambda的主體是一個reduce:(funcall fi(funcall fi-1 ...)),操作數以相反順序恢復初始值。

1)最外層lambda表達式的作用是什麼?也就是說,它從哪裏得到它的「參數」呢?它是指定爲解構綁定的第一個參數的數據結構嗎? 2)最裏面的lambda從哪裏來的呢?

我的意思是我可以欣賞代碼的作用,但詞法範圍對我來說仍然有點神祕。 期待任何和所有的評論! 在此先感謝, // Marco

+0

爲什麼所有吊架? – Marcin

+1

我的歉意,我沒有看到這個討論在http://stackoverflow.com/questions/5928106/compose-example-in-paul-grahams-ansi-common-lisp – ocramz

+0

@Marcin,引導眼睛; )這是不好的做法?我仍然是一個noob – ocramz

回答

10

它可能更容易,如果你首先考慮幾個實際的例子:

(defun compose1 (a) 
    (lambda (&rest args) 
    (apply a args))) 

(defun compose2 (a b) 
    (lambda (&rest args) 
    (funcall a (apply b args)))) 

(defun compose3 (a b c) 
    (lambda (&rest args) 
    (funcall a (funcall b (apply c args))))) 

所以最lambda是返回值:一個使用任何參數的函數,它用它做什麼,正在申請最後一個函數並將所有其他函數按照與上一個函數得到的結果相反的順序鏈接起來。

注:compose1可以更簡單地定義爲(defun compose1 (a) a)

一個有點相當於但效率較低的版本可能是

(defun compose (&rest functions) 
    (if (= (length functions) 1) 
     (car functions) 
     (lambda (&rest args) 
     (funcall (first functions) 
       (apply (apply #'compose (rest functions)) 
         args))))) 
+0

謝謝你們的例子和解釋,這個明確說明問題! – ocramz

2

1)最外層的lambda爲您創建閉包,因爲(combine ...)的結果是一個調用其他函數組合的函數。

2)最裏面的lambda從函數reduce獲取ists參數。 Reduce採用兩個參數的函數(最裏面的lambda)並逐步將其應用於列表,例如,

(reduce #'- '(1 2 3 4)) is (- (- (- 1 2) 3) 4)