2013-10-17 169 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)