繁体   English   中英

计划延续 - 需要解释

[英]scheme continuations -need explanation

以下示例涉及跳转到延续和退出。 有人可以解释功能的流程。 我围绕延续移动了一圈,并且不知道函数的入口和出口点。

(define (prod-iterator lst)
  (letrec ((return-result empty)
        (resume-visit (lambda (dummy) (process-list lst 1)))
        (process-list
         (lambda (lst p)
           (if (empty? lst)
               (begin
                 (set! resume-visit (lambda (dummy) 0))
                 (return-result p))
               (if (= 0 (first lst))
                   (begin
                     (call/cc ; Want to continue here after delivering result     
                      (lambda (k)
                        (set! resume-visit k)
                        (return-result p)))
                     (process-list (rest lst) 1))
                   (process-list (rest lst) (* p (first lst))))))))
    (lambda ()
      (call/cc
       (lambda (k)
         (set! return-result k)
         (resume-visit 'dummy))))))

(define iter (prod-iterator '(1 2 3 0 4 5 6 0 7 0 0 8 9)))
(iter) ; 6                                                                        
(iter) ; 120                                                                      
(iter) ; 7                                                                        
(iter) ; 1                                                                        
(iter) ; 72                                                                       
(iter) ; 0                                                                        
(iter) ; 0

谢谢。

该过程迭代一个列表,将非零成员相乘,并在每次找到零时返回结果。 Resume-visit存储继续处理列表的其余部分, return-result继续迭代器的调用站点。 在开始时,定义resume-visit来处理整个列表。 每一个零被发现时,继续被捕获,其中,当被调用执行(process-list (rest lst) 1)的任何值lst在当时。 当列表用尽时, resume-visit设置为虚拟过程。 而且,每次程序调用iter ,它都会执行以下操作:

(call/cc
   (lambda (k)
     (set! return-result k)
     (resume-visit 'dummy)))

也就是说,它捕获调用者的延续,调用它会向调用者返回一个值。 存储继续,程序跳转以处理列表的其余部分。 当过程调用resume-visit ,进入循环,当调用return-result时,退出循环。

如果我们想更详细地检查process-list ,我们假设列表是非空的。 该过程采用基本递归,累积结果直到找到零。 此时, p是累计值, lst是包含零的列表。 当我们有一个像(begin (call/cc (lambda (k) first)) rest)的构造时,我们首先执行first表达式,其中k绑定到一个continuation。 它是一个在调用时执行rest表达式的过程。 在这种情况下,存储该延续并调用另一个继续,它将累积的结果p返回给iter的调用者。 将在下次调用iter调用该延续,然后循环继续执行列表的其余部分。 这是延续的要点,其他一切都是基本的递归。

你需要记住的是,对(call/cc f)将把作为参数传递的函数f应用于call/cc到当前的continuation。 如果在函数f内部使用某个参数a调用该延续,则执行将转到相应的call/cc ,并且参数a将作为该call/cc的返回值返回。

您的程序在变量return-result存储“ call/cc iter call/cc in iter ”的继续,并开始处理列表。 它在遇到前0之前将列表的前3个非零元素相乘。当它看到0时,继续“处理列表元素0”存储在resume-visit ,值p返回到continuation return-result通过调用(return-result p) 此调用将使执行返回到itercall/cc ,并且该call/cc返回p的传递值。 所以你看到第一个输出6。

其余的对iter调用是相似的,并且会使执行在这两个延续之间来回传递。 手动分析可能有点大脑扭曲,您必须知道恢复延续时的执行上下文。

你可以这样做:

(define (prod-iter lst) (fold * 1 (remove zero? lst)))

......即使它只能通过一次遍历也能表现得更好。

对于延续,召回(双关语)所有呼叫/ cc所做的是等待以这种方式应用“k”:

(call/cc (lambda (k) (k 'return-value)))
  => return-value

这里的诀窍是你可以让call / cc返回它自己的continuation,这样它就可以在call / cc返回之后应用到别处:

;; returns twice; once to get bound to k, the other to return blah
(let ([k (call/cc (lambda (k) k))]) ;; k gets bound to a continuation
  (k 'blah)) ;; k returns here
  => blah

这样可以通过将延迟保存在变量中来使连续返回多次。 Continuations只返回它们应用的值。

闭包是在参数与它们绑定之前携带其环境变量的函数。 他们是普通的lambdas。

延续传递样式是一种将闭包作为参数传递以便稍后应用的方法。 我们说这些闭包参数是延续的。 这里是来自我的数独生成器/解算器的当前代码的一半,作为示例演示了延续传递样式如何简化算法:

#| the grid is internally represented as a vector of 81 numbers
example: (make-vector 81 0)

this builds a list of indexes |#
(define (cell n) (list (+ (* (car 9) (cadr n))))
(define (row n) (iota 9 (* n 9)))
(define (column n) (iota 9 n 9))
(define (region n)
  (let* ([end (+ (* (floor-quotient n 3) 27)
                 (* (remainder n 3) 3))]
         [i (+ end 21)])
    (do ([i i
          (- i (if (zero? (remainder i 3)) 7 1))]
         [ls '() (cons (vector-ref *grid* i) ls)])
      ((= i end) ls))))

#| f is the continuation

usage examples:
(grid-ref *grid* row 0)
(grid-set! *grid* region 7) |#
(define (grid-ref g f n)
  (map (lambda (i) (vector-ref g i)) (f n)))
(define (grid-set! g f n ls)
  (for-each (lambda (i x) (vector-set! g i x))
    (f n) ls))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM