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

时间:2012-11-12 04:54:26

标签: scheme coroutine callcc 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))))) 

多余的工作:

 ;; 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) 

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

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

看起来这个代码不会起作用!实际发生了。或者是集!这段代码必须工作吗?

正在进行的视觉表现确实会有所帮助。

1 个答案:

答案 0 :(得分:4)

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

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

好的,当我第一次尝试理解call/cc时,我发现这个代码极端混乱,所以让我们看一个简化的协程示例:

(define r1
  (lambda (cont)
    (display "I'm in r1!")
    (newline)
    (r1 (call/cc cont))))

(define r2
  (lambda (cont2)
    (display "I'm in r2!")
    (newline)
    (r2 (call/cc cont2))))

好的,与您的代码完全相同的概念。但它更简单。

在这种情况下,如果我们调用(r1 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    
I'm in r1
I'm in r2
...

为什么呢?因为r1首先将r2作为cont接收,所以它向我们宣布它在r1中。然后它使用(call/cc cont)又名(call/cc r2)的结果来自行处理。

好的,这是什么回报?好(call/cc r2)将开始执行r2并宣布它在r2中,然后使用(call/cc cont2)的结果递归自身。那么什么是cont2呢?在cont2之前,r1是该表达式的延续。因此,当我们在这里调用它时,我们将延续传递回我们当前所在的位置。然后我们忘记了我们在r2中做了什么,然后跳回执行r1。

现在在r1重复。我们宣布一些东西,然后跳回到我们之前在r2中的位置和之前的表达式,(call/cc cont2)返回我们在r1的位置继续,然后我们继续我们的快乐无限循环。 / p>

返回您的代码

在您的代码中,概念完全相同。实际上,当您停下来思考它时,superfluous-computation几乎与上述功能完全相同。那么set! s有什么用呢?在这段代码中,他们所做的就是将do-other-work的值更改为最新的延续。而已。在我的例子中,我使用了递归。在此示例中,他们使用set!