我们发现这个函数构建器可以实现P.Graham的“ANSI Common Lisp”(第110页)中的组合。 参数是n> 0引用的函数名。我完全不明白,所以我会在这里引用代码并在其下面指出我的问题:
(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',其余元素绑定到'rest'。 最外层lambda的主体是reduce :( funcall fi(funcall fi-1 ...)),操作数按反转顺序恢复初始值。
1)最外层lambda表达式的作用是什么?也就是说,它从哪里获得'args'?它是指定为destructuring-bind的第一个参数的数据结构吗? 2)最里面的lambda从哪里获取它的两个参数?
我的意思是我可以欣赏代码的功能,但词法范围对我来说仍然有点神秘。 期待任何和所有评论! 提前致谢, // Marco
答案 0 :(得分:11)
如果你先考虑几个实际例子,那可能会更容易:
(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
是返回值:一个接受任何参数的函数,它对它的作用是应用最后一个函数,并以最后一个函数得到的结果以相反的顺序链接所有其他函数。 / p>
注意: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)))))
答案 1 :(得分:2)
1)最外面的lambda为你创建一个闭包,因为(combine ...)的结果是一个函数来计算其他函数的组成。
2)最里面的lambda从函数reduce获得ists参数。 Reduce采用两个参数的函数(最里面的lambda)并将其逐步应用于列表,例如
(reduce #'- '(1 2 3 4)) is (- (- (- 1 2) 3) 4)