收集器功能如何在Scheme中工作?

时间:2016-11-26 13:58:40

标签: scheme lisp racket continuation-passing the-little-schemer

我无法理解Scheme中收集器功能的使用。我正在使用这本书" The Little Schemer" (由Daniel P. Friedman和Matthias Felleisen撰写)。一个有一些解释的综合例子对我有很大帮助。使用收集器函数的函数示例如下:

(define identity
  (lambda (l col)
    (cond
      ((null? l) (col '()))
      (else (identity (cdr l)
                      (lambda (newl)
                        (col (cons (car l) newl)))))))

...示例调用为(identity '(a b c) self)self-function(define self (lambda (x) x))identity函数返回给定列表l,因此给定调用的输出将为(a b c)。使用的确切语言是R5RS Legacy语言。

2 个答案:

答案 0 :(得分:5)

鉴于那些"收藏家"函数在identity定义中定义,调用

(identity xs col)

对于任何列表xs和一些"收集器"函数col等同于调用

(col xs)

所以相同的列表将被"返回"即通过其论点"收藏家" / continuation function col。这解释了它的名字,identity,然后。

为了进行比较,reverse可以编码为

(define reverse     ; to be called as e.g. (reverse l display)
  (lambda (l col)
    (cond
      ((null? l) (col '()))        ; a reversed empty list is empty
      (else (reverse (cdr l)       ; a reversed (cdr l) is newl --
                     (lambda (newl)    ; what shall I do with it when it's ready?
                       (col            ; append (car l) at its end and let col
                          (append newl                           ; deal with it!
                                  (list (car l))))))))))

这种编程风格称为continuation-passing style:每个函数都传递一个" continuation"假设它将传递其余计算的结果,以便原始的continuation / collector函数最终将传递给最终结果。每个收集者的论点代表未来"结果"它将接收,然后收集器函数本身指定如何处理然后

不要对术语感到困惑:这些功能不是"延续"由call/cc函数捕获,它们是正常的Scheme函数,代表"接下来要做什么"。

该定义可以理解为

identity :
  to transform a list xs 
        with a collector function col,
    is 
    | to call (col xs)                              , if xs is empty, or
    | to transform (cdr xs)  
        with a new collector function col2  
        such that
              (col2 r)  =  (col (cons (car xs) r))  , otherwise.

(或者我们可以用伪代码写这个),

(identity list col)  =
  | empty? list           ->  (col list)
  | match? list (x . xs)  ->  (identity xs col2)
                                where 
                                (col2 r)  =  (col (cons x r))

col2通过将r传递给前一个处理程序(cons x r)来处理其参数col。这意味着r会转换为(cons x r),但不会将其作为值返回,而是将其输入col进行进一步处理。因此,我们"返回"将新值(cons x r)传递给前一个"收集器"。

示例通话,如图所示:

(identity (list 1 2 3) display)     

= (identity (list 2 3) k1)
      ; k1 =  (lambda (r1) (display (cons 1 r1)))           =  display ° {cons 1}

= (identity (list 3)  k2)
      ; k2 =  (lambda (r2) (k1 (cons 2 r2)))                     =  k1 ° {cons 2} 

= (identity (list )  k3)
      ; k3 =  (lambda (r3) (k2 (cons 3 r3)))                     =  k2 ° {cons 3} 

= (k3 '())                        ; (((display ° {cons 1}) ° {cons 2}) ° {cons 3}) []

= (k2 (cons 3 '()))                    ; ((display ° {cons 1}) ° {cons 2}) [3]

= (k1 (cons 2 (list 3)))                    ; (display ° {cons 1}) [2,3]

= (display (cons 1 (list 2 3)))                  ; display [1,2,3]

= (display (list 1 2 3))

更新:在模式匹配的伪代码我最近喜欢使用,我们可以写

identity []        col  =  col []
identity [a, ...d] col  =  identity d ( newl =>  col [a, ...newl] )

reverse  []        col  =  col []
reverse  [a, ...d] col  =  reverse  d ( newl =>  col [...newl, a] )

希望在视觉上非常明显,几乎不需要解释!

答案 1 :(得分:0)

我添加第二个答案是希望它可以弄清您是否有其他疑问(如缺少“可接受”标记表示)。

在Gerber J. Sussman的声音中,正如在SICP讲座中所听到/看到的一样,这些视频可以在网上和网上找到,我们在编写时可以阅读,

(define identity

“身份”定义为

  (lambda

该函数(在给定

时)
           (l col)

两个参数lcol

    (cond
      ((null? l)

-如果(null? l)为真-

  • 好的,这意味着l是一个列表, NB

                   (col '()))
    

返回表达式(col '())

的值
  • 好的,这意味着col是一个函数,期望一个参数,作为一种可能性,一个空列表,
      (else (identity (cdr l)

否则它将使用更新后的值进行尾部递归调用,其中一个为(cdr l)

                      (lambda (newl)
                        (col (cons (car l) newl)))))))

和另一个新构造的函数,例如,当 it 时将使用其参数newl(如col所期望的那样调用列表,因为它以相同的角色出现,必须遵循相同的约定),然后依次调用函数col non-empty 列表,该列表是通过将(car l)前缀到列表newl

因此,此函数identity遵循方程式

( identity   (cons (car l) (cdr l))           col                        )
==
( identity       (cdr l)     (lambda (newl)  (col  (cons (car l) newl))) )

( identity   '()   col )
==
( col        '()       )

描述一个迭代过程,该过程使函数调用

(identity [a,      b,      c, ...,    n]    col      )

加入通话

(col
     (cons a (cons b (cons c ... (cons n '()) ... ))))

重新创建相同的精确列表,然后将其作为参数提供给已提供的函数col