所以我第一次在lua中遇到协程的概念,lua的实现或多或少是可以理解的。我现在正在学习scheme,我明白相同的功能是通过call/cc实现的,但是我有一点我很难弄清楚如何才能实现这一目标。有人知道简单的教程或有关该主题的内容吗?
Matt Might 写了一篇关于延续的很好的介绍,其中包括关于协程的部分:
Matt Might 的链接很好,我上次访问rosettacode wiki 中的 Amb 实现时访问过该链接。但对于协程来说,它只是显示
lua 使用 yield, resume
c2 wiki
(coroutine routine)
很有帮助,它是非对称的(如上面的 QA 链接所示,非对称版本可以通过一个额外的调度程序实现对称)。
该非对称版本不允许在协程本身中使用协程之间传递数据,但我们可以通过在 cond
中添加子句并使用
call/cc
传递值来进行一些修改来实现这一点。 (请参阅以下
(current passed-arg)
上下文。)
(define (coroutine routine)
(let ((current routine)
(status 'suspended))
(lambda args
(cond ((null? args)
(if (eq? status 'dead)
(error 'dead-coroutine)
(let ((continuation-and-value
(call/cc (lambda (return)
(let ((returner
(lambda (value)
(call/cc (lambda (next)
(return (cons next value)))))))
(current returner)
(set! status 'dead))))))
(if (pair? continuation-and-value)
(begin (set! current (car continuation-and-value))
(cdr continuation-and-value))
continuation-and-value))))
((eq? (car args) 'status?) status)
((eq? (car args) 'dead?) (eq? status 'dead))
((eq? (car args) 'alive?) (not (eq? status 'dead)))
((eq? (car args) 'kill!) (set! status 'dead))
(true nil)))))
(define test-coroutine-1
(coroutine (lambda (yield)
(print "HELLO!")
(yield 1)
(print "WORLD!")
(yield 2)
(print "SORRY, I'M OUT"))))
;; added
(define print write-line)
(test-coroutine-1 'status?)
; suspended
(test-coroutine-1 'dead?)
; #f
(test-coroutine-1 'alive?)
; #t
(test-coroutine-1)
; "HELLO!"
; 1
(test-coroutine-1)
; "WORLD!"
; 2
(test-coroutine-1)
; "SORRY, I'M OUT"
(test-coroutine-1 'status?)
; dead
(test-coroutine-1 'dead?)
; #t
(test-coroutine-1)
; . error: dead-coroutine
这里用了2个call/cc
,
return
就是用
yield
退出协程,做完某件事之后再返回到另一个协程(即这里的交互程序)。
next
是使用一个
value
后存储之前的悬挂位置。然后当稍后
再次
调用
(test-coroutine-1)
时,我们将从之前使用value
的位置继续运行,例如:
(yield 1)
被分配为
returner
,因为
(current returner)
,其中
current
之前被分配为
next
。
yield
行为意味着我们可以在
cond
中添加一个
(current passed-arg)
子句,这样
(yield foo)
就会按预期被分配到
passed-arg
,从而实现通信。 因此,
“协程的基本特征”(即保留数据和控制历史记录)是通过 call/cc 实现的。