这个Scheme列表迭代器如何使用call-with-current-continuation?

时间:2011-04-12 02:25:58

标签: iterator scheme continuations

我正在尝试阅读此代码:

(define list-iter
  (lambda (a-list)
    (define iter
      (lambda ()
        (call-with-current-continuation control-state)))
    (define control-state
      (lambda (return)
        (for-each
          (lambda (element)
            (set! return (call-with-current-continuation
                           (lambda (resume-here)
                             (set! control-state resume-here)
                             (return element)))))
          a-list)
        (return 'list-ended)))
    iter))

有人可以解释call-with-current-continuation在这个例子中是如何运作的吗?

由于

3 个答案:

答案 0 :(得分:3)

call-with-concurrent-continuation或简称call/cc的本质是在程序执行期间获取检查点或延续的能力。然后,您可以通过将它们应用为函数来返回这些检查点。

这是一个不使用延续的简单示例:

> (call/cc (lambda (k) (+ 2 3)))
5

如果你不使用延续,很难区分。以下是我们实际使用它的一些内容:

> (call/cc (lambda (k) (+ 2 (k 3))))
3
> (+ 4 (call/cc (lambda (k) (+ 2 3))))
9
> (+ 4 (call/cc (lambda (k) (+ 2 (k 3)))))
7

当调用continuation时,控制流会跳回到call/cc抓取延续的位置。将call/cc表达式想象为一个洞,它被传递给k的任何内容填充。

list-itercall/cc的使用要复杂得多,可能是开始使用它的难点。首先,这是一个示例用法:

> (define i (list-iter '(a b c)))
> (i)
a
> (i)
b
> (i)
c
> (i)
list-ended
> (i)
list-ended

以下是正在发生的事情的草图:

  1. list-iter返回无参数i的过程。
  2. 调用i时,我们会立即抓住延续并将其传递给control-state。当调用绑定到return的延续时,我们将立即返回调用i的任何人。
  3. 对于列表中的每个元素,我们获取一个新的延续并用新的延续覆盖control-state的定义,这意味着我们将在下一步出现时从那里继续。
  4. 在下次设置control-state之后,我们将列表的当前元素传递回return延续,从而产生列表元素。
  5. 再次调用i时,请从步骤2开始重复,直到for-each完成整个列表的工作。
  6. 使用return调用'list-ended续页。由于control-state未更新,因此每次调用'list-ended时都会一直返回i
  7. 正如我所说,这是call/cc的相当复杂的用法,但我希望这足以通过这个例子。为了更加温和地介绍延续,我建议选择The Seasoned Schemer

答案 1 :(得分:0)

基本上它需要一个函数f作为参数,并将f应用于程序的当前上下文/状态。

来自维基百科:
(define (f return)
 (return 2)
 3)

(display (f (lambda (x) x))) ; displays 3

(display (call-with-current-continuation f)) ; displays 2

所以基本上在没有当前连续(cc)的情况下调用f时,函数应用于2,然后返回3.当使用current-continuation时,参数应用于2,这会强制程序跳转到调用current-continuation的点,从而返回2.它可用于生成返回或暂停执行流。

如果您了解C,请按照以下方式考虑:在C中,您可以使用指向函数的指针。你也有一个返回机制。假设返回采用了函数所采用的相同类型的参数。假设您可以获取其地址并将该地址存储在变量中或将其作为参数传递,并允许函数返回给您。它可以用来模仿抛出/捕获,或者作为协同程序的机制。

答案 2 :(得分:0)

这基本上是:

(define (consume)
  (write (call/cc control)))

(define (control ret)
   (set! ret (call/cc (lambda (resume)
                        (set! control resume)
                        (ret 1))))
   (set! ret (call/cc (lambda (resume)
                        (set! control resume)
                        (ret 2))))
   (set! ret (call/cc (lambda (resume)
                        (set! control resume)
                        (ret 3)))))

(consume)
(consume)
(consume)

希望它更容易理解。