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

CPU*_*Fry 8 lisp scheme the-little-schemer continuation-passing racket

我无法理解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))))))))
Run Code Online (Sandbox Code Playgroud)

......有一个例子叫做存在(identity '(a b c) self)self-function存在(define self (lambda (x) x)).该identity函数返回给定的列表l,因此给定调用的输出将是(a b c).使用的确切语言是R5RS Legacy语言.

Wil*_*ess 5

给定如何在定义中identity定义那些"收集器"函数,调用

(identity xs col)
Run Code Online (Sandbox Code Playgroud)

对于任何列表xs和一些"收集器"功能col,相当于调用

(col xs)
Run Code Online (Sandbox Code Playgroud)

所以相同的列表将被"返回",即传递给它的参数"collector"/ continuation函数col.那就解释了它的名字identity.

为了比较,a 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))))))))))
Run Code Online (Sandbox Code Playgroud)

这种编程风格称为延续传递风格:每个函数都传递一个"延续",假定它将传递其余计算的结果,以便原始的延续/收集器函数将传递给最终结果最终.每个收藏家的说法代表了未来的"结果",它将接收和收集功能本身,然后指定它是如何被处理,然后.

不要被术语搞糊涂:这些函数不是函数捕获的"延续" 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.
Run Code Online (Sandbox Code Playgroud)

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

(identity list col)  =
  | empty? list           ->  (col list)
  | match? list (x . xs)  ->  (identity xs col2)
                                where 
                                (col2 r)  =  (col (cons x r))
Run Code Online (Sandbox Code Playgroud)

col2r通过传递(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))
Run Code Online (Sandbox Code Playgroud)

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

identity []        col  =  col []
identity [a, ...d] col  =  identity d ( newl =>  col [a, ...newl] )
Run Code Online (Sandbox Code Playgroud)

reverse  []        col  =  col []
reverse  [a, ...d] col  =  reverse  d ( newl =>  col [...newl, a] )
Run Code Online (Sandbox Code Playgroud)

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