【问题标题】:What exactly is a "continuation prompt?"究竟什么是“继续提示”?
【发布时间】:2015-07-02 12:26:02
【问题描述】:

我正在尝试破译the documentation

call-with-continuation-prompt

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

我理解它说“将proc 应用于给定的args 并具有当前延续”的部分,然后从那里开始就是胡言乱语。

延续被“扩展”是什么意思,“提示”是如何“扩展”的?

【问题讨论】:

    标签: scheme racket continuations delimited-continuations


    【解决方案1】:

    从概念上讲,什么是提示?

    Scheme 通常具有 延续 的概念,但 Racket 用 分隔延续 的理念扩展了这一点。延续的想法是它捕获剩余的计算。我不会试图解释一般的延续,因为这超出了这个问题的范围。

    不过,我将解释是什么让 delimited 延续变得特别。通常,捕获延续会捕获整个计算,一直到顶层。这使得它们在实现复杂的控制结构方面的使用相对有限,因为应用延续将完全释放对程序执行的控制。

    使用定界延续,您只能捕获延续的特定部分。实际捕获的评估部分由 prompts 分隔,它们的作用类似于当前延续中的标记,指定要捕获多少延续。

    好的,但这是什么意思?

    与未定界延续相比,如果没有实际看到它的实际作用,定界延续的概念并不清楚。

    标准(非定界)延续

    考虑以下示例代码。

    (define *k* #f)
    
    (sqrt
     (+ 1 2 3
        (call/cc
         (λ (k)
           (set! *k* k)
           0))))
    

    这段代码非常简单——它捕获一个延续并存储到全局绑定*k*。延续本身看起来像这样:

    (sqrt (+ 1 2 3 _))
    

    (其中_表示调用延续时要填充的“洞”。)

    应用此延续将完全按照预期工作。

    > (*k* 3) ; evaluates (sqrt (+ 1 2 3 3))
    3
    

    这一切都很普通。那么分隔延续带来的区别是什么?

    定界延续

    如果我们只想捕获*k* 中延续的部分,该怎么办。例如,如果我们只想捕捉这种延续怎么办?

    (+ 1 2 3 _) ; the inner portion of the last continuation
    

    我们可以通过建立一个延续提示来做到这一点,这将调整实际捕获的延续的多少。

    (sqrt
     (call-with-continuation-prompt
      (λ ()
        (+ 1 2 3
           (call/cc
            (λ (k)
              (set! *k* k)
              0))))))
    

    现在,应用*k* 给出内部结果:

    > (*k* 3)
    9
    

    分隔延续的类比

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

    评估模型是一个堆栈——每个函数调用都会将一个新帧压入堆栈,从函数返回时会将该帧从堆栈中弹出。我们可以将调用堆栈可视化为一堆卡片。

    通常,当一个延续被捕获时,它会捕获当前帧和所有它下面的帧,如下图所示。

    以蓝色表示的顶层未被捕获。它实际上是分隔系统中的默认提示。

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

    这个分隔符界定延续的范围。

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

    这是定界延续的基础知识,但还有其他方法可以控制延续,从而为延续系统提供更多权力(以及保护其免受恶意代码的侵害),这些是提示标记和延续障碍。

    提示标记的概念本质上是一个标记给定提示的“标签”。使用上面的卡片类比,每个透明分隔器都可以被赋予一个标签。然后,当您捕获一个延续时,您可以指定一直捕获到该特定标签,即使中间有其他带有其他标签的提示。

    另一方面,

    持续障碍是一种安全措施。就像提示一样,它们可以可视化为位于调用堆栈元素之间的“分隔符”,但它们不是用作控制堆栈被捕获多少的标记,而是用作防止继续“跳过”障碍。

    有关这方面的更多详细信息,请考虑阅读the section in the Racket reference on continuation barriers。摘录如下:

    具体来说,只有在替换不引入任何延续障碍时,才能将延续替换为另一个延续。它只能通过跳转到作为当前延续尾部的延续来消除延续障碍。因此,延续屏障可防止“向下跳跃”进入受屏障保护的延续。

    【讨论】:

    • 您是如何绘制这些图形的?当然,您没有时间在 Photoshop 中手动绘制。
    • @ThrowawayAccount3Million 这正是我所做的!我认为,它们的质量低到足以使其可行。 :P
    • 如果了解这些,我会节省很多时间。我通过在闭包中包装常规延续来实现这个概念。当被调用时,闭包会将它们自己的延续传递回原来的延续,精确地创建一个分隔延续的效果。
    猜你喜欢
    • 2012-05-04
    • 2014-10-28
    • 2012-08-27
    • 2010-11-12
    • 2011-03-18
    • 2011-01-22
    • 1970-01-01
    相关资源
    最近更新 更多