Recursion 这个小阴谋家甚至只是个小阴谋家;有限公司
我很难理解第145页小阴谋家的Recursion 这个小阴谋家甚至只是个小阴谋家;有限公司,recursion,lambda,scheme,continuation-passing,the-little-schemer,Recursion,Lambda,Scheme,Continuation Passing,The Little Schemer,我很难理解第145页小阴谋家的evens only*&co示例到底发生了什么 代码如下: (define evens-only*&co (lambda (l col) (cond ((null? l) (col '() 1 0)) ((atom? (car l)) (cond ((even? (car l)) (evens-only*&co (cdr l) (lambda
evens only*&co
示例到底发生了什么
代码如下:
(define evens-only*&co
(lambda (l col)
(cond
((null? l)
(col '() 1 0))
((atom? (car l))
(cond
((even? (car l))
(evens-only*&co (cdr l)
(lambda (newl product sum)
(col (cons (car l) newl)
(opx (car l) product)
sum))))
(else
(evens-only*&co (cdr l)
(lambda (newl product sum)
(col newl product (op+ (car l) sum)))))))
(else
(evens-only*&co (car l)
(lambda (newl product sum)
(evens-only*&co (cdr l)
(lambda (dnewl dproduct dsum)
(col (cons newl dnewl)
(opx product dproduct)
(op+ sum dsum))))))))))
初始的列可以是:
(define evens-results
(lambda (newl product sum)
(cons sum (cons product newl))))
我没有得到的是,使用l
as((1)23)
,它会立即进入最后的,否则(car l)
as(1)
和(cdr l)
as(2 3)
。很好,但是我的脑子一片空白,试图从newl
,product
,sum
中整理出dnewl
,dproduct
,sum
。如果有人能指导我如何设置DrRacket或Chez方案或MIT方案来运行步进机,那也会很有帮助
但也许我太早了。第一次读这篇文章的初学者真的应该理解这篇疯狂的续篇吗?我第一次读这篇文章时也感到困惑,直到我在其他地方读到了关于续篇和续篇传递风格(这就是它)的内容后才开始理解它
冒着解释您已经得到的信息的风险,一种帮助我理解它的方法是将“收集器”或“continuation”视为替换函数返回值的正常方式。在正常的编程风格中,您调用一个函数,接收一个值,并在调用者中对其进行处理。例如,标准递归length
函数包括非空大小写的表达式(+1(长度(cdr列表))
。这意味着一旦(length(cdr list))
返回一个值,就会有一个计算等待它产生的任何值,我们可以将其视为(+1[返回值])
。在普通编程中,解释器会跟踪这些挂起的计算,就像你在本书的前几章中看到的那样,这些计算往往会“叠加”。例如,在递归计算列表的长度时,我们有一个“等待计算”嵌套,其深度与列表的长度相同
在continuation传递样式中,我们不调用函数并在调用函数中使用返回的结果,而是通过向函数提供要调用的“continuation”来告诉函数在生成其值时要做什么。(这类似于在异步Javascript编程中对回调的处理,例如:不编写result=someFunction();
而是编写someFunction(function(result){…})
,所有使用result
的代码都在回调函数中)
以下是延续传球风格的长度
,仅供比较。我调用了continuation参数return
,它应该建议它在这里如何工作,但请记住,它和其他任何变量一样,只是一个普通的Scheme变量。(在这种样式中,continuation参数通常称为k
)
在中阅读此类代码有一个有用的提示。(见第8页开始的第II-5节)。解释一下,上面的else
条款是这样说的:
假设您在(cdr lis)
上调用length/k
的结果
调用它cdr len
,然后添加一个并传递此添加的结果
继续(返回
)
请注意,这几乎正是解释器在函数的正常版本中计算(+1(长度(cdr-lis))
时必须做的事情(除了它不必给中间结果命名(长度(cdr-lis))
)(和中间值的名称)显式,而不是让解释器跟踪它
让我们将此方法应用于evens only*&co
中的每个子句。由于此函数生成三个值而不是一个值,所以这里有点复杂:删除奇数的嵌套列表;偶数的乘积;奇数的和。这是第一个子句,其中(car l)
已知为偶数:
(evens-only*&co (cdr l)
(lambda (newl product sum)
(col (cons (car l) newl)
(opx (car l) product)
sum)))
假设你有去除奇数的结果,
将偶数相乘,并从列表的cdr
中添加奇数,
并分别称它们为newl
、product
和sum
在newl
上的列表头(因为它是偶数,所以应该是
在结果中);将乘积
乘以列表的标题(自
我们正在计算偶数的乘积);让sum
单独处理;然后传递这些
将三个值添加到您的等待续集col
在这种情况下,列表的开头是一个奇数:
(evens-only*&co (cdr l)
(lambda (newl product sum)
(col newl product (op+ (car l) sum))))
与前面一样,但是将相同的newl
和product
值连同sum
和列表头一起传递给continuation(即“返回”它们),因为我们将奇数相加
这里是最后一个,其中(car l)
是一个嵌套列表,它由于双重递归而稍微复杂一些:
(evens-only*&co (car l)
(lambda (newl product sum)
(evens-only*&co (cdr l)
(lambda (dnewl dproduct dsum)
(col (cons newl dnewl)
(opx product dproduct)
(op+ sum dsum))))))
假设您得到了删除、求和和
将(l车)
中的数字称为newl
、product
和sum
;然后
假设您对(cdr l)
执行相同操作时得到的结果,
并将它们称为dnewl
、dproduct
和dsum
,以供您的等待
继续,给出由cons
ingnewl
和dnewl
(因为我们正在生成一个列表列表);相乘
product
和dproduct
;并添加sum
和dsum
注意:每次进行递归调用时,我们都为递归调用构造一个新的延续,它“关闭”当前值
(evens-only*&co (car l)
(lambda (newl product sum)
(evens-only*&co (cdr l)
(lambda (dnewl dproduct dsum)
(col (cons newl dnewl)
(opx product dproduct)
(op+ sum dsum))))))
(define (evens-only&co l)
(local ((define (processing-func sum prod evlst lst)
(cond ((null? lst) (cons sum (cons prod evlst)))
((atom? (car lst))
(cond ((even? (car lst)) (processing-func sum (* prod (car lst)) (append evlst (list (car lst))) (cdr lst)))
(else
(processing-func (+ sum (car lst)) prod evlst (cdr lst)))))
(else
(local ((define inner-lst (processing-func sum prod '() (car lst))))
(processing-func (car inner-lst) (cadr inner-lst) (append evlst (list (cddr inner-lst))) (cdr lst)))))))
(processing-func 0 1 '() l)))
'((9 1 2 8) 3 10 ((9 9) 7 6) 2)
(define the-last-friend
(lambda (newl product sum)
(cons sum (cons product newl))
)
)
evens-only*&co l col
= col [] 1 0 , IF null? l
= evens-only*&co (cdr l)
( newl product sum =>
col (cons (car l) newl)
(opx (car l) product)
sum ) , IF atom? (car l) && even? (car l)
= evens-only*&co (cdr l)
( newl product sum =>
col newl product (op+ (car l) sum) ) , IF atom? (car l)
= evens-only*&co (car l)
( anewl aproduct asum =>
evens-only*&co (cdr l)
( dnewl dproduct dsum =>
col (cons anewl dnewl)
(opx aproduct dproduct)
(op+ asum dsum) ) ) , OTHERWISE
evens-only*&co [[5], 2, 3, 4] col
=
col (cons [] ; original structure w only the evens kept in,
(cons 2 ; for the car and the cdr parts
(cons 4 [])))
(opx 1 ; multiply the products of evens in the car and
(opx 2 (opx 4 1))) ; in the cdr parts
(op+ (op+ 5 0) ; sum, for the non-evens
(op+ 3 0))
evens-only*&co = g where
g [a, ...xs...] col
| pair? a = g a ( la pa sa =>
g xs ( ld pd sd =>
col [la, ...ld...] (* pa pd) (+ sa sd) ) )
| even? a = g xs ( l p s => col [ a, ...l... ] (* a p ) s )
| otherwise = g xs ( l p s => col l p (+ a s ) )
g [] col = col [] 1 0