我想了解如何在没有call/cc
的情况下实现 coroutines 。
我从这个小例子开始,了解如何修改代码,以便我可以在没有call/cc
的情况下使用它:
(define x 0)
( + 2 (call-with-current-continuation
(lambda (cont)
(set! x cont)
3)))
(x 4)
当我执行call/cc
函数时,它给我 5 ,然后执行(x 4)
时 6 。
我使用此功能替换call/cc
:
(define (call/cc-cps f continuation)
(f continuation continuation))
我尝试将此功能更改为CPS(继续传递样式):
(call/cc-cps
(lambda (exit cont)
(set! x cont)
3)
(lambda (value)
(+ value 2)))
但是当我执行它时,而不是 5 我得 3 。但我确实使用(x 4)
6 。
答案 0 :(得分:1)
使用CPS,您不会有顶级延续提示,因此为了进行比较,您需要将代码放在空的内容中,如下所示:
(let ()
(define x 0)
(+ 2 (call-with-current-continuation
(lambda (cont)
(set! x cont)
3))) ; ==> 5
(x 4))
; ==> 6
; ==> 6
; ==> 6
; ... forever
由于您每次在求和后调用(x 4)
,因此这将成为一个无限循环。
;; CPS-version of +
(define (+& a b continuation)
(continuation (+ a b)))
注意&amp ;.它用于表示该函数需要一个额外的参数,即延续。在CPS中,您可以像这样定义call/cc
:
(define (call/cc& f& continuation)
(define (exit& value actual-continuation)
(continuation value))
(f& exit& continuation))
请注意,它与您的版本完全不同。它将退出函数传递给f&
,而不是使用传递的actual-continuation
来执行所有剩余的计算,而是将其传递给call/cc&
的延续。
现在我们可以将您的程序重写为:
((lambda (x& halt-continuation)
(call/cc& (lambda (cont continuation)
((lambda (ingnored-undefined-value) (continuation 3))
(set! x& cont)))
(lambda (three)
(+& 2 three (lambda (ignored-result)
(x& 4 halt-continuation))))))
0 values)
ignored-result
第一次为5
,其余为4
ignored-result
计算的无限次为6
,就像在非CPS版本中一样与let
。
我使用DrRacket,它有一个非常好的调试器,你可以步骤,看看究竟发生了什么。我在+&
来电时添加了一个断点,然后点击|>
,看到变量three
拳头为3
,然后4
无限次。
CPS并不容易。 call/cc
为我们提供了CPS的好处,而不会使代码更难以阅读。在没有call/cc
的情况下实现协同程序对我来说很难写,因为我开始使用call/cc
这一点非常复杂,特别是因为如果你不是非常小心,你会有一个无限循环。