程序开始时的当前继续

时间:2017-12-30 00:21:54

标签: scheme racket continuations

创建返回过程显然是可以使用continuation创建的常见示例,如以下示例所示:

(define (find-multiple factor)
  (let/cc return
    (for ([num (shuffle (range 2000))])
      (when (zero? (modulo num factor))
        (return num)))))

(find-multiple 43)

(来自https://beautifulracket.com/explainer/continuations.html#what-are-they-good-for

虽然我有点理解,但是开头的继续是返回从某个值调用过程的地方,我不知道延续实际上是什么样的。在下面的例子中,我可以想象它的样子:

(define c #f)
(+ 1 (+ 2 (+ 3 (+ (let/cc here (set! c here) 4) 5)))) ; 15
(c 20) ; 31

延续是:

(lambda (something)
  (+ 1 (+ 2 (+ 3 (+ something 5))))

因此表达式被包装成lambda,let/cc被lambda的输入参数替换。

但是通过返回程序,我不知道正确的思考方式是什么,以及延续实际上是什么样的。

1 个答案:

答案 0 :(得分:3)

首先关闭let/cc只是call/cc的语法糖。这些是平等的:

(let/cc here 
  (set! c here) 4)

(call/cc 
 (lambda (here) 
   (set! c here) 4))

所有代码无论你如何编写它都将以特定方式运行,每个操作将执行一步,然后调用程序其余部分的继续。这样:

(define c #f)
(+ 1 (+ 2 (+ 3 (+ (let/cc here (set! c here) 4) 5)))) ; 15
(c 20) ; 31

变成这样的事情:

((lambda (c k)
   (call/cc&
    (lambda (here k)
      (set! c here)
      (k 4))
    (lambda (v)
      (+& v 5 (lambda (a1)
                (+& 3 a1 (lambda (a2)
                           (+& 2 a2 (lambda (a3)
                                      (+& 1 a3 (lambda (a4)
                                                 (c 20 k))))))))))))
 #f values)

现在请注意,现在这里的顺序是显式的,并且首先处理最深层的表达式,因为所有其他的表达式首先依赖于它的值。另请注意,延续时间包括每次调用(c 20)

以下是使用过程的CPS版本:

(define (+& a b k)
  (k (+ a b)))

(define (call/cc& f k)
  (f (lambda (v ign-k) (k v)) k))

最后一个也许是你见过的最明确的call/cc实现。虽然代码中的那个看起来很神秘,因为代码不是连续传递样式,在Scheme系统使CPS call/cc之后甚至不会被认为是原语。

对于(find-multiple 43),延续只是显示结果的REPL。如果您在(+ 1 (find-multiple 43))之类的地方使用过它,则延续时间为(lambda (v) (+& 1 v halt))

修改

一个更简单的例子:

(let ((x (read)))
  (display 
   (call/cc 
    (lambda (return)
      (- 4 (if (< x 4) x (return 10))))))))

现在当你运行它并且你输入一个低于4的值时,call/cc部分没有被使用,但是如果它没有注意到这发生在它应该做的下一件事是从4中减去它。在CPS中它看起来像这样:

(read&
 (lambda (x)
   (call/cc& 
    (lambda (return& k)
      (define (k- v)
        (-& 4 v k))
      (<& x 4 (lambda (p)
                (if p
                    (k- x)
                    (return& 10 k-)))))                          
    (lambda (v)
      (display& v values)))))

这里又是&amp; -procedures。这些可能已经开始变得熟悉并且可以预测:

(define (<& a b k) (k (< a b)))
(define (-& a b k) (k (- a b)))
(define (display& v k) (k (display v)))
(define (read& k) (k (read)))