Continuation(延续)描述了接下来发生的某个值,对吗? 这难道不仅仅是一个接受值并执行某些计算的函数吗?
(+ (* 2 3) 5)
(* 2 3)
的结果是 (+ _ 5)
(define k (lambda (v) (+ v 5)))
在这里使用 call/cc
有什么意义,而不使用函数 k
?
Continuation(延续)描述了接下来发生的某个值,对吗? 这难道不仅仅是一个接受值并执行某些计算的函数吗?
(+ (* 2 3) 5)
(* 2 3)
的结果是 (+ _ 5)
(define k (lambda (v) (+ v 5)))
在这里使用 call/cc
有什么意义,而不使用函数 k
?
正确。所有程序在停止之前都有延续。一个延续通常是底层实现所执行的计算中的一步。
你的例子:
(+ (* 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))))
call/cc
会自动完成这个过程,不需要您重新构造代码。call/cc
函数方便地捕获当前配置并将其封装成一个函数。当调用该函数时,您将回到计算中的那一点。因此,continuation与函数非常不同(但continuation函数本身是一个函数)。call/cc
应用于两种常见情况:(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
call/cc
,它的参数接受当前续体(作为一个函数)。编辑你的问题,使用call/cc
!阅读维基页面上的续体。 - Basile Starynkevitch