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
和.这相当于#'list
2
(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 次 |
最近记录: |