【问题标题】:Can call-with-current-continuation be implemented only with lambdas and closures?只能使用 lambdas 和闭包来实现 call-with-current-continuation 吗?
【发布时间】:2011-04-18 04:59:53
【问题描述】:

有谁知道call/cc 是否可以仅使用 lambda 和闭包来实现?

似乎call/cc 中断了程序的流程(就像一个异常),但 lambda 和闭包不能这样做。因此我认为call/cc 不能通过 lambdas 和闭包来实现。

还有什么想法吗?

【问题讨论】:

  • 不,要获得完整的持续支持(iow 不是单次支持的),您将需要堆栈和堆捕获。这一切都发生在非常低​​的水平上。
  • @leppie 我很乐意将其作为答案。
  • @Frank Shearar:如果我真的成功实现了它们,我会 :) 继续很难,我们去购物吧!
  • Seaside 人(3.0 之前的版本)作弊:访问堆栈后,他们只需遍历激活记录并将它们混合到流中。在重新激活延续时,他们解开流并继续。

标签: lisp computer-science scheme continuations callcc


【解决方案1】:

这个问题不是特别清楚,因为“仅用 lambda 和闭包实现”到底是什么意思?

在任何情况下,通过手动写入continuation passing style,可以在任何带有闭包的语言中使用延续。然后可以通过扩展编译器来实现自动翻译成这种形式,Lisps 通常允许通过宏在用户级别上实现。例如,请参阅 cl-cont,这是一个为 Common Lisp 实现延续的库,这是一种没有内置它们的语言。

像 Scheme 中的高效普遍延续很可能在直接处理程序堆栈的较低级别上实现,但这不是要求,只是优化。

【讨论】:

  • CPS 仅在底层语言支持尾调用时才有效(在 Scheme 的情况下它应该支持)。
  • 通常是这样,但原则上您可以通过将延续和参数向上返回到某个“CPS 驱动程序”循环来手动擦除堆栈帧。
  • CPS 可以工作,但问题是它适用于您控制的代码(并且可以 CPS)。例如,处理库变得困难,因为您需要将它们视为外来调用,即使它们使用您的语言。 (顺便说一句,那些“SPC 驱动程序循环”通常被称为 tampolining。)
  • common lisp with-call/cc 真的提供了方案延续的全部功能吗?此页面表明它受到限制/限制:common-lisp.net/project/bese/docs/arnesi/html/…
  • 据我了解,没有。它实际上只是一个语法抽象,但你无法在它之上实现真正的协程之类的东西。
【解决方案2】:

在 Scheme 中,您可以在转换为延续传递样式 (CPS) 时使用 lambda 实现 call/cc。转换为 CPS 时,call/cc 的每次出现都可以替换为以下等效项:

(lambda (f k) (f (lambda (v k0) (k v)) k))

其中k 是要保存的延续,(lambda (v k0) (k v)) 是恢复此延续的转义过程(无论在调用时处于活动状态的延续k0 都将被丢弃)。

所以,回答你对 Scheme 的问题:是的,可以做到。

【讨论】:

  • 这就是 call/cc 通常在像 Scheme 这样的尾调用优化语言上实现的方式吗?作为一个宏?
  • @Byte 不,它不像宏那样实现,而是在低级解释器中,通过在调用 call/cc 时复制堆栈。有关更多详细信息,请参阅如何将延续实现为第一类对象。这就是call/cc 所做的。
猜你喜欢
  • 2014-08-02
  • 2019-03-19
  • 2011-08-03
  • 2017-08-16
  • 1970-01-01
  • 2014-09-04
  • 1970-01-01
  • 2012-06-02
  • 1970-01-01
相关资源
最近更新 更多