7

这与什么是呼叫/抄送有关?,但我不想为了自己的目的劫持这个问题,并且它的一些论点(例如与 setjmp/longjmp 的类比)回避了我。

我想我对什么是延续有足够的了解,我认为它是当前调用堆栈的快照。我不想讨论为什么这可能很有趣,或者你可以用延续做什么。我的问题更具体地说,为什么我必须为 call/cc 提供函数参数?为什么 call/cc 不只返回当前的延续,所以我可以用它做任何我想做的事情(存储它,调用它,你命名它)?在另一个问题的链接(http://community.schemewiki.org/?call-with-current-continuation-for-C-programmers)中,它谈到“本质上这只是一种让您继续的干净方式并避开后续跳回保存点的方式。”,但我不明白。这似乎是不必要的复杂。

4

4 回答 4

9

如果你使用像 Jay 展示的结构,那么你可以抓住延续,但在某种程度上,被抓住的价值已经被破坏了,因为你已经在那个延续中。相反,call/cc可用于获取在当前表达式之外仍悬而未决的延续。例如,延续的最简单用途之一是实现一种 an abort

(call/cc (lambda (abort)
           (+ 1 2 (abort 9))))

你不能用你描述的操作来做到这一点。如果你尝试一下:

(define (get-cc) (call/cc values))
(let ([abort (get-cc)]) (+ 1 2 (abort 9)))

然后你会得到一个关于9作为程序申请的错误。发生这种情况是因为用新值abort跳回到-- 这意味着您现在正在执行第二轮相同的加法表达式,除了 now绑定到...let9abort9

两个额外的相关说明:

  1. 有关延续的实用介绍,请参阅PLAI
  2. call/cc 有点复杂,因为它包含一个函数——一个概念上更易于使用的构造是let/cc您可以在 PLT Scheme 等一些实现中找到的构造。上面的例子变成了(let/cc abort (+ 1 2 (abort 9))).
于 2009-07-14T03:45:09.530 回答
2

那将不那么通用。如果你想要这种行为,你可以这样做:

(call/cc (lambda (x) x))

您可以查看“Darrell Ferguson 和 Dwight Deugo。“使用当前延续模式调用”中的延续示例用法。第 8 届程序模式语言会议。2001 年 9 月。( http://library.readscheme.org/page6.html ) 并尝试使用上面定义的 call/cc-return 重写它们。

于 2009-07-13T14:57:33.513 回答
2

我建议从问自己开始:成为一流的延续意味着什么?

一个表达式的延续本质上由两条数据组成:第一,该表达式的闭包(即环境);其次,表示应该如何处理表达式的结果。因此,具有一流延续的语言是一种具有封装这些部分的数据结构,并且像对待其他任何数据结构一样对待这些数据结构的语言。

call/cc 是实现这个想法的一种特别优雅的方式:当前的延续被打包为一个过程,该过程封装了what-is-to-be-done-with-the-expression,即该过程在应用于表达式时所做的事情;以这种方式表示延续仅仅意味着这个过程的闭包包含它被调用的站点的环境。

你可以想象以其他方式实现一流延续的想法。它们不会是 call/cc,而且我很难想象这样的表示如何更简单。

顺便说一句,考虑一下 Eli 提到的 let/cc 的实现,我更喜欢称之为 bind/cc:

(define-syntax bind/cc
    (syntax-rules ()
        ((bind/cc var . body)
             (call/cc (lambda (var) . body)))))

作为练习,您将如何基于 bind/cc 实现 call/cc?

于 2009-12-04T19:39:25.050 回答
2

针对常见的 SO 网络礼节,我正在回答我自己的问题,但更多的是作为编辑而不是答案的提供者。

过了一会儿,我在LtU开始了一个类似的问题。毕竟,这些都是整天思考语言设计的人,不是吗,我终于找到了答案之一。现在,这里提到的事情,例如 Eli 或原始问题中提到的,对我来说更有意义。这完全取决于延续中包含的内容,以及应用延续的位置。

LtU的一张海报写道:

“您可以确切地看到 call/cc 如何让您“不碍事。”使用 em 或 get/cc 您需要进行某种测试以确定您是否有后跳或只是初始呼叫。基本上, call/cc 将延续的使用保留在延续之外,而对于 get/cc 或 em,延续包含其使用,因此(通常)您需要在延续的开头添加测试(即紧随 get /cc / em) 将“使用延续部分”与“延续的其余部分”分开。”

那把它带回家了。

无论如何,谢谢你们!

于 2009-12-07T22:30:30.833 回答