究竟什么是"延续提示?"

Thr*_*unt 24 scheme continuations racket delimited-continuations

我正在尝试破译文档

call-with-continuation-prompt

适用proc于给定的args,当前延续由提示扩展.提示标记为prompt-tag,必须是default-continuation-prompt-tag(默认)或的结果make-continuation-prompt-tag.结果proccall-with-continuation-prompt调用的结果.

我理解它所说的"适用procarg当前延续的给定s"的部分,然后它就是那里的乱码.

对于延续"延伸"甚至意味着什么,以及"提示"如何"延伸"?

Ale*_*ing 45

概念上什么是提示?

方案一般都有延续的想法,但是Racket以分隔连续的思想扩展了它.延续的想法是它捕获剩余的待计算的计算.我不会试图解释一般的延续,因为这超出了这个问题的范围.

但是,我将解释是什么使定界延续特殊.通常,捕获延续会捕获整个计算,一直到顶层.这使得它们的用法相对受限于实现复杂的控制结构,因为应用延续将完全释放对程序执行的控制.

使用分隔的延续,您只能捕获延续的某个部分.实际捕获的评估部分由提示分隔,提示在当前延续中用作标记,用于指定要捕获的连续数量.

好的,但这有什么意义呢?

与无限延续相比,实际上没有实际看到分界延续的概念并不十分明确.

标准(非分隔)延续

请考虑以下示例代码.

(define *k* #f)

(sqrt
 (+ 1 2 3
    (call/cc
     (? (k)
       (set! *k* k)
       0))))
Run Code Online (Sandbox Code Playgroud)

此代码非常简单 - 它捕获延续并存储到全局绑定中*k*.延续本身看起来像这样:

(sqrt (+ 1 2 3 _))
Run Code Online (Sandbox Code Playgroud)

(_代表在调用延续时要填写的"洞".)

应用此延续将完全按照人们的预期工作.

> (*k* 3) ; evaluates (sqrt (+ 1 2 3 3))
3
Run Code Online (Sandbox Code Playgroud)

这一切都非常普通.那么分隔延续带来的差异是什么?

定界延续

如果我们只是想捕捉部分的延续*k*.例如,如果我们只想捕捉这种延续怎么办?

(+ 1 2 3 _) ; the inner portion of the last continuation
Run Code Online (Sandbox Code Playgroud)

我们可以通过建立延续提示来完成此操作,该提示将调整实际捕获的连续数量.

(sqrt
 (call-with-continuation-prompt
  (? ()
    (+ 1 2 3
       (call/cc
        (? (k)
          (set! *k* k)
          0))))))
Run Code Online (Sandbox Code Playgroud)

现在,申请*k*给出了内在的结果:

> (*k* 3)
9
Run Code Online (Sandbox Code Playgroud)

分隔延续的类比

延续可能是一个有点抽象的概念,因此如果上面的代码示例不是很清楚,请考虑这个类比.

评估模型是一个堆栈 - 每个函数调用都会将一个新帧推送到堆栈上,并且从函数返回会将该帧从堆栈中弹出.我们可以将调用堆栈可视化为一堆卡片.

通常,当捕获延续时,它会捕获当前帧及其下方的所有帧,如下图所示.

顶部以蓝色表示,未捕获.它实际上是分隔系统中的默认提示.

但是,安装新提示会在帧之间创建一种透明分隔符,这会影响作为延续的一部分捕获哪些帧.

该分隔符界定了延续的范围.

附录:提示标签和延续障碍

这是分隔延续的基础,但是还有其他方法可以控制延续,为延续系统提供更多的功能(以及保护它免受恶意代码),这些是快速标记和延续障碍.

提示标记的想法本质上是标记给定提示的"标签".使用上面的卡片类比,每个透明分隔器都可以给出一个标签.然后,当您捕获延续时,您可以指定捕获所有返回到该特定标签的方式,即使其他提示中包含其他标签也是如此.

另一方面,延续障碍是一种安全措施.就像提示一样,它们可以被视为位于调用堆栈元素之间的"分隔符",但不是用作控制堆栈捕获量的标记,而是用作防止连续跳过"跳过"的堆栈.屏障.

有关此问题的更多详细信息,请参阅关于延续障碍的球拍参考中的部分.这是一段摘录:

具体而言,只有当替换不引入任何延续障碍时,延续才能被另一个替换.它可以仅通过跳转到当前延续的尾部的延续来消除延续障碍.因此,延续屏障防止"向下跳跃"进入受屏障保护的延续.

  • 请将这些图表添加到Racket文档中. (5认同)
  • 了解这些可以节省我很多时间。我通过将常规延续包装在闭包中一次来实现这个概念。当被调用时,闭包会将它们自己的延续传递回原始延续,从而准确地创建分隔延续的效果。 (2认同)