sun*_*nwc 13 lisp reduce closures common-lisp paul-graham
任何人都可以在Paul Graham的ANSI Common Lisp第110页中解释一个例子吗?
该示例尝试解释use&rest和lambda来创建函数式编程工具.其中之一是构成函数参数的函数.我找不到任何解释它是如何工作的东西.代码如下:
(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)))))
Run Code Online (Sandbox Code Playgroud)
用法是:
(mapcar (compose #'list #'round #'sqrt)
'(4 9 16 25))
Run Code Online (Sandbox Code Playgroud)
输出是:
((2) (3) (4) (5))
Run Code Online (Sandbox Code Playgroud)
2号线和6号线对我来说看起来特别神奇.任何意见将不胜感激.
该compose函数返回一个闭包,从最后到第一个调用每个函数,将每个函数调用的结果传递给下一个.
调用得到的闭包(compose #'list #'round #'sqrt)首先计算其参数的平方根,将结果舍入为最接近的整数,然后创建结果列表.用say 3作为参数调用闭包等同于评估(list (round (sqrt 3))).
该解构绑定评估(reverse fns)表达式获得的参数compose以相反的顺序,并结合所产生的列表中的其第一项的fn1的局部变量和结果列表的所述其余部分其余部分局部变量.因此,FN1持有的最后一个项目FNS,#'sqrt.
在减少每个调用fns与累积结果的函数.该:initial-value (apply fn1 args)提供的初始值到reduce功能并支持调用具有多个参数的闭合.没有多个参数的要求,compose可以简化为:
(defun compose (&rest fns)
#'(lambda (arg)
(reduce #'(lambda (v f) (funcall f v))
(reverse fns)
:initial-value arg)))
Run Code Online (Sandbox Code Playgroud)
destructuring-bind结合了析构函数和绑定.析构函数是一种允许您访问数据结构的一部分的函数.car并且cdr是简单的析构函数来提取列表的头部和尾部.getf是一个通用的析构函数框架.绑定通常由以下方式执行let.在这个例子中,fns是(#'list #'round #'sqrt)(的参数compose),因此(reverse fns)是(#'sqrt #'round #'list).然后
(destructuring-bind (fn1 . rest) '(#'sqrt #'round #'list)
...)
Run Code Online (Sandbox Code Playgroud)
相当于
(let ((tmp '(#'sqrt #'round #'list)))
(let ((fn1 (car tmp))
(rest (cdr tmp)))
...))
Run Code Online (Sandbox Code Playgroud)
tmp当然,除了它没有约束力.我们的想法destructuring-bind是它是一个模式匹配结构:它的第一个参数是数据必须匹配的模式,模式中的符号绑定到相应的数据部分.
现在fn1是#'sqrt和rest现在(#'round #'list).该compose函数返回一个函数:(lambda (&rest args) ...).现在考虑将该函数应用于某些参数时会发生什么4.lambda可以应用,屈服
(reduce #'(lambda (v f) (funcall f v))
'(#'round #'list)
:initial-value (apply #'sqrt 4)))
Run Code Online (Sandbox Code Playgroud)
该apply函数适用fn1于参数; 因为这个参数不是一个列表,所以这就是(#'sqrt 4)它2.换句话说,我们有
(reduce #'(lambda (v f) (funcall f v))
'(#'round #'list)
:initial-value 2)
Run Code Online (Sandbox Code Playgroud)
现在该reduce函数完成了它的工作,即从开始#'(lambda (v f) (funcall f v))依次应用于#'round和.这相当于#'list2
(funcall #'list (funcall #'round 2))
? (#'list (#'round 2))
? '(2)
Run Code Online (Sandbox Code Playgroud)
好的,这里是:
(#'sqrt #'round #'list)),然后将第一个项目粘贴到其中fn1,其余部分粘贴到其中rest.我们有:fn1= #'sqrt,和rest= (#'round #'list).(apply sqrt args)(args给出的结果为lambda的值)作为初始值,并且每次迭代都会抓取下一个函数rest来调用.
(round (apply sqrt args))的第二次迭代(list (round (apply sqrt args))).sqrt允许初始函数(在您的情况下)采用多个参数.其余函数仅使用单个参数调用,即使链中的任何特定函数执行多值返回也是如此.| 归档时间: |
|
| 查看次数: |
1339 次 |
| 最近记录: |