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

标签 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本质上就变成了一个执行多余计算代码然后跳转到set后面的位置的过程! (A点)。第二次,它将“跳转到 B 点”行为围绕“跳转到 A 点并执行上下文,或 A 点后面的任何代码”。这是正确的吗?

如果设置的话,这段代码似乎不起作用!确实发生了。或者是套装!这段代码需要工作吗?

以视觉方式呈现正在发生的事情确实很有帮助。

最佳答案

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

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

在这种情况下,如果我们调用 (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首先接收r2cont2所以它向我们宣布它位于 r1 。然后它 self 递归,结果为 (call/cc cont2)又名 (call/cc r2) .

好的,那么这个的返回值是什么呢?嗯(call/cc r2)来电 r2 当前延续cont1所以会宣布它在 r2然后递归自身,结果为 (call/cc cont1) 。好的,那么 cont1 是什么?再次? cont1是之前 r1 中该表达式的延续。因此,当我们在这里调用它时,我们会将延续传递回我们当前所在的位置。然后我们就忘记了我们在r2中所做的一切。并跳回执行 r1 .

这在 r1 中重复现在。我们宣布一些内容,然后跳回之前的位置 r2和我们之前的表达,(call/cc cont1)返回到我们在 r1 的位置的延续然后我们继续我们快乐的无限循环。

返回您的代码

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

关于方案:嵌套调用/抄送如何为协程工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13338559/

相关文章:

javascript - 延续和回调有什么区别?

functional-programming - 有什么方法可以进行基于示例的编程吗?

scheme - 寻找更清晰的方法来从数字列表中创建关联列表

clojure - 如何实现原始程序 "apply"

python-3.x - 在 Python 3.5 中,关键字 "await"是否等同于 "yield from"?

python - 协程与 python 中的类

node.js - Node.js 流可以做成协程吗?

lambda - 什么是调用/抄送?

racket - 如何在 Racket 中开始捕获当前的延续

scheme - 如何在 Lilypond 中缩写 'note with the same note an octave higher, parenthesized'?