Recursion 这个小阴谋家甚至只是个小阴谋家;有限公司

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

我很难理解第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 (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
ing
newl
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