一个 continuation 和一个函数有何区别?

5

Continuation(延续)描述了接下来发生的某个值,对吗? 这难道不仅仅是一个接受值并执行某些计算的函数吗?

(+ (* 2 3) 5)

(* 2 3) 的结果是 (+ _ 5)

。这段代码涉及到IT技术相关内容。
(define k (lambda (v) (+ v 5)))

在这里使用 call/cc 有什么意义,而不使用函数 k


你没有使用call/cc,它的参数接受当前续体(作为一个函数)。编辑你的问题,使用call/cc!阅读维基页面上的续体 - Basile Starynkevitch
我没有使用call/cc,而是使用一个等效的函数来表示continuation(续延)? - ayhid
Continuation在语法上是一个函数,但它代表了控制转移。它的调用协议与函数不同 - 它永远不应该返回。 - Will Ness
3个回答

6

正确。所有程序在停止之前都有延续。一个延续通常是底层实现所执行的计算中的一步。

你的例子:

(+ (* 2 3) 5)

组合操作符 + 依赖于组合操作符 * 的先完成。因此,(+ result 5) 确实是 (* 2 3) 的延续。在这种情况下,它不是一个过程。使用 call/cc 的好处在于,当你有一个你后悔的延续时,想要做其他事情,或者你想在以后回来处理它。让我们先看第一个:
(define g 0)
(call/cc 
  (lambda (exit)
    (/ 10 (if (= g 0) (exit +Inf.0) g))))

很明显,在if的结果得出后,存在一个延续操作,但由于运行了exit,整个过程就被短路返回+Inf.0。

如果使用过程实现,而不想在之后进行除法运算,该怎么做呢?在这种风格下,你无法实现。

这并不是魔法,因为Scheme会将你的代码转换成Continuation Passing Style(=CPS),在CPS中调用call/cc没有特殊之处。在CPS中编写代码并不是一件平凡的事情。

以下是call/cc的CPS定义:

(define (kcall/cc k consumer)
  (consumer k (lambda (ignore v) (k v))))

4
恭喜!您刚刚发明了延续传递风格(continuation-passing style)!你所做的唯一区别就是call/cc会自动完成这个过程,不需要您重新构造代码。

2
“Continuation”是计算的整个未来。在计算中,每个点都有一个continuation,可以简单地将其视为当前程序计数器和当前堆栈。Scheme的call/cc函数方便地捕获当前配置并将其封装成一个函数。当调用该函数时,您将回到计算中的那一点。因此,continuation与函数非常不同(但continuation函数本身是一个函数)。
通常会看到call/cc应用于两种常见情况:
1. 非局部退出。您建立了一个continuation,进行一些计算,要突然结束计算,可以调用continuation。
2. 重新启动/重新进入计算。在这种情况下,您保存continuation,然后随意再次调用它。
以下是第一种情况的示例:
(begin
  ;; do stuff
  (call/cc (lambda (k)
              ;; do more

             ;; oops, must 'abort'
             (k 'ignore)))
  ;; continue on
  )

这里有一个关于第二种情况的示例:
> (define c #f)
> (let ((x 10))
   (display (list (+ 1 (call/cc (lambda (k) (set! c k) x))) 111))
   (display " more"))
(11 111) more
> (c 20)
(21 111) more
> (c 90)
(91 111) more

对于这个案例#2,值得注意的是,使用 continuation 会带您回到顶层的读取-求值-打印循环 - 这给了您在此示例中重新调用 continuation 的机会!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接