延续与函数的区别



Continuation用一些值描述接下来会发生什么,对吧?这不就是一个取一个值并进行一些计算的函数吗?

(+ (* 2 3) 5)

(* 2 3)的延续是(+ _ 5)

(define k (lambda (v) (+ v 5)))

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

True。所有程序都有延续,直到它停止。一个延续通常是底层实现进行计算的一个步骤。

你的例子:

(+ (* 2 3) 5)

组合+取决于组合*以获得第一名。因此CCD_ 5实际上是CCD_ 6的延续。不过,在这种情况下,这不是一个过程。call/cc的有用之处在于,当你有一个延续时,你会后悔并想做其他事情,或者你想在以后再回来。让我们做第一个:

(define g 0)
(call/cc 
  (lambda (exit)
    (/ 10 (if (= g 0) (exit +Inf.0) g))))

显然,当if的结果完成时,有一个除法是连续的,但由于运行了exit,整个过程短路,返回+Inf.0。

如果不让它在事后进行除法运算,你怎么能用一个程序做到这一点?在这种风格下,你不能。

这其实并不神奇,因为Scheme将您的代码转换为ContinuationPassingStyle(=CPS),并且在CPS中调用/cc也没有什么特别之处。在CPS中编写代码并非易事。

以下是call/cc 的CPS定义

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

祝贺您!你刚刚发明了连续传球风格!您所做的与call/cc的唯一区别在于,call/cc是自动完成的,不需要重新构造代码。

"continuation"是计算的全部未来。计算中的每个点都有一个延续,简单地说,你可以把它看作是当前程序计数器和当前堆栈。Scheme call/cc函数方便地捕获当前配置并将其打包为一个函数。当您调用该函数时,您将返回到计算中的那个点。因此,连续性与函数非常不同(但连续性函数是函数)。

通常有两种常见的情况可以看到call/cc的应用:

  1. 非本地出口。建立一个连续性,进行一些计算,以突然结束调用该连续性的计算。

  2. 重新启动/重新输入计算。在这种情况下,您保存延续,然后根据需要再次调用它。

以下是案例#1的示例:

(begin
  ;; do stuff
  (call/cc (lambda (k)
              ;; do more
             ;; oops, must 'abort'
             (k 'ignore)))
  ;; continue on
  )

下面是案例#2的一个例子:

> (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会将您带回顶级的read-eval-print循环,这使您有机会在本例中重新调用continuation!

最新更新