【问题标题】:Can the CPS-styled `call/cc` be written in terms of a hypothetical non-CPS-styled `cc'`?CPS 风格的 `call/cc` 是否可以用假设的非 CPS 风格的 `cc'` 来编写?
【发布时间】:2019-12-13 03:31:40
【问题描述】:

在支持延续的语言中,例如Scheme、Ruby 和 Haskell,假设有一个函数 cc',它不接受任何参数并返回当前的延续,因此通过调用 cc' 获得延续的调用者可以在任何地方调用延续,只要它喜欢.

cc' 可以写成 CPS 风格的 call/cc,通过将标识函数作为参数传递给 call/cc

相反,CPS 风格的 call/cc 可以写成非 CPS 风格的 cc' 吗?

【问题讨论】:

  • call/cc(f) = f(cc)?
  • @rampion 这很直观,但错误(AFAICS)。这会导致g(call/cc(f)) = g(f(cc)) = call/cc(g . f),其中最后一个. 表示函数组合,这显然不是我们想要的。关键是,直观地说,f 应该接收“没有f 本身”的延续,而f(cc) 在延续中包含f
  • Haskell 原生支持延续。可以在语言中实现定界延续(例如,ContT r monad 转换器和各种 CPSish 事物,如 Codensity),但不支持像 Scheme 那样的未定界延续。

标签: ruby haskell scheme continuations continuation-passing


【解决方案1】:

这是我的尝试(警告:我是一个没有经验的策划者)。让get-cc 成为返回当前延续的函数。

(define (get-cc)
  (call-with-current-continuation (lambda (k) k)))

那么,我们可以定义:

(define (callCC f)
  (let ((w (get-cc)))
    (if (pair? w)
      (car w)
      (f (lambda (x) (w (cons x '())))))))

第一次调用此函数时,w 绑定到当前延续。所以,(pair? w) 是假的,我们调用f 并继续(lambda (x) (w (cons x '()))

当通过f(带有参数(cons x '()))调用w 时,再次输入let 的主体,其中w 现在绑定到(cons x '())。 现在,(pair? w) 为真,我们可以返回(car w),即x

pair wrapper 用于区分什么是“f 的延续”和“结果来自 f”,可以这么说。

快速测试表明这是有效的,但我并不完全相信它的正确性。

您可能注意到w 绑定到不同类型的值。这就是为什么我使用像 Scheme 这样的无类型语言而不是 Haskell。

【讨论】:

    猜你喜欢
    • 2020-04-09
    • 1970-01-01
    • 2018-01-27
    • 2010-12-21
    • 2011-02-16
    • 2020-01-06
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    相关资源
    最近更新 更多