【问题标题】:How does this Scheme list iterator use call-with-current-continuation?这个 Scheme 列表迭代器如何使用 call-with-current-continuation?
【发布时间】:2011-08-03 12:53:36
【问题描述】:

我正在尝试阅读这段代码:

(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 在这个例子中是如何工作的?

谢谢

【问题讨论】:

  • SO 上可能有无数其他“什么是呼叫/抄送”问题的重复。我能找到的最规范、最有帮助的一个:stackoverflow.com/questions/612761/what-is-call-cc
  • 我认为这个使用yield-like 模式的特定示例非常有用,可以独立使用。不过,也许它应该重新命名。

标签: iterator scheme continuations


【解决方案1】:

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

当调用延续时,控制流跳回到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 的定义,这意味着我们将在下一次出现第 2 步时从那里继续。
  4. 在为下一次设置 control-state 之后,我们将列表的当前元素传递回 return 延续,生成列表的一个元素。
  5. 当再次调用 i 时,从第 2 步开始重复,直到 for-each 完成整个列表的工作。
  6. 使用'list-ended 调用return 延续。由于control-state 没有更新,因此每次调用i 时都会不断返回'list-ended

正如我所说,这是call/cc 的一个相当复杂的用法,但我希望这足以通过这个例子。对于延续的更温和的介绍,我建议选择The Seasoned Schemer

【讨论】:

    【解决方案2】:

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

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

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

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

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

    如果您了解 C,请这样想:在 C 中,您可以获取指向函数的指针。你也有一个返回机制。假设 return 采用了与函数采用相同类型的参数。假设您可以获取其地址并将该地址存储在变量中或将其作为参数传递,并允许函数为您返回。它可以用来模拟 throw/catch,或者作为协程的一种机制。

    【讨论】:

      【解决方案3】:

      这本质上是:

      (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)
      

      希望它更容易理解。

      【讨论】:

        猜你喜欢
        • 2019-03-19
        • 2014-08-02
        • 2011-04-18
        • 2015-03-27
        • 1970-01-01
        • 1970-01-01
        • 2012-04-05
        • 2011-05-09
        • 2021-12-01
        相关资源
        最近更新 更多