方案:嵌套调用/ cc如何为协程工作?

hxn*_*sun 5 scheme callcc coroutine continuation

我在http://community.schemewiki.org/?call-with-current-continuation中查看以下关于协程的示例:

 (define (hefty-computation do-other-stuff) 
    (let loop ((n 5)) 
      (display "Hefty computation: ") 
      (display n) 
      (newline) 
      (set! do-other-stuff (call/cc do-other-stuff)) ; point A
      (display "Hefty computation (b)")  
      (newline) 
      (set! do-other-stuff (call/cc do-other-stuff)) 
      (display "Hefty computation (c)") 
      (newline) 
      (set! do-other-stuff (call/cc do-other-stuff)) 
      (if (> n 0) 
          (loop (- n 1))))) 
Run Code Online (Sandbox Code Playgroud)

多余的工作:

 ;; notionally displays a clock 
 (define (superfluous-computation do-other-stuff) 
    (let loop () 
      (for-each (lambda (graphic) 
                  (display graphic) 
                  (newline) 
                  (set! do-other-stuff (call/cc do-other-stuff))) 
                '("Straight up." "Quarter after." "Half past."  "Quarter til.")) ; point B
      (loop))) 


(hefty-computation superfluous-computation) 
Run Code Online (Sandbox Code Playgroud)

对于call/cc的第一次使用,应该是什么上下文?当我说上下文时,我的意思是,由于callcc的跳转,我们应该"返回"哪里?

根据我的理解,第一次调用call/cc时,do-other-stuff实际上变成了执行多余计算代码的过程,然后跳转到集合之后的那个点!(A点).第二次,它将围绕"跳转到A点并执行上下文,或者点A之后的任何代码"包围其"跳转到B点"行为.它是否正确?

看起来这个代码似乎没有效果!实际发生了.或者是集!这段代码必须工作吗?

对正在发生的事情的直观表示将真正有所帮助.

Dan*_*zer 4

的上下文call/cc是从哪里call/cc调用的。您几乎可以想到call/cc类似的方法goto,将代码直接跳回之前的位置并替换(call/cc whatever)为返回值。

call/cc基本上是说,“让我们去做这个功能,然后把它放弃,然后跳回这里,忘记它正在做的其他事情”

call/cc好吧,当我第一次尝试理解时,我发现这段代码非常令人困惑,所以让我们看一个简化的协程示例:

(define r1
  (lambda (cont2)
    (display "I'm in r1!")
    (newline)
    (r1 (call/cc cont2      ))))
    ;  ^---------------cont1

(define r2
  (lambda (cont1)
    (display "I'm in r2!")
    (newline)
    (r2 (call/cc cont1      ))))
    ;  ^---------------cont2
Run Code Online (Sandbox Code Playgroud)

好的,这与您的代码完全相同的概念。但它要简单得多。

在这种情况下,如果我们称其(r1 r2)为 prints

I'm in r1
I'm in r2
I'm in r1
I'm in r2    
I'm in r1
I'm in r2    
I'm in r1
I'm in r2
...
Run Code Online (Sandbox Code Playgroud)

为什么?因为r1首先接受r2ascont2所以它向我们宣布它在r1. 然后它以(call/cc cont2)aka的结果自行递归(call/cc r2)

好的,那么这个的返回是什么?Well(call/cc r2) 调用r2 当前的延续as cont1so 将宣布它已进入r2,然后以 的结果递归自身(call/cc cont1)。好吧,那cont1又是什么?cont1是之前该表达式的延续r1。因此,当我们在这里调用它时,我们会将延续传递回我们当前所在的位置。然后我们忘记了我们正在做的任何事情r2并跳回执行r1

现在又重复这样的情况r1。我们宣布一些事情,然后跳回到我们之前的位置r2,我们的表达式从之前开始,(call/cc cont1)返回一个延续到我们所在的位置r1,然后我们继续我们快乐的无限循环。

回到你的代码

在您的代码中,概念完全相同。事实上,当你停下来想一想,‘多余计算’和上面的函数几乎是一样的。那么“set!”是怎么回事?在这段代码中,他们所做的就是将“do-other-work”的值更改为最新的延续。就是这样。在我的示例中,我使用了递归。在此示例中,他们使用“set!”。