如何检测Tcl协同路由的完成?

如何检测Tcl协同路由的完成?,tcl,coroutine,Tcl,Coroutine,我想在Tcl中找到一种很好的方法来检测协同进程的结束。考虑: coroutine cor apply {{} { yield 1 yield 2 yield 3 }} try { puts [cor] puts [cor] puts [cor] puts [cor] } trap {TCL LOOKUP COMMAND cor} {e} { puts "done" } 这是可行的,但它感觉像一个黑客,它是脆弱的。如果我重命名co

我想在Tcl中找到一种很好的方法来检测协同进程的结束。考虑:

coroutine cor apply {{} {
    yield 1
    yield 2
    yield 3
}}

try {
    puts [cor]
    puts [cor]
    puts [cor]
    puts [cor]
} trap {TCL LOOKUP COMMAND cor} {e} {
    puts "done"
}
这是可行的,但它感觉像一个黑客,它是脆弱的。如果我重命名
cor
并忘记在陷阱中重命名它,它将失败。如果我在陷阱中遗漏
cor
,它将捕获不相关的打字错误


一定有更好的办法。它是什么?

要检测命令是否仍然存在,请使用
info commands
并检查它返回的列表的长度。(我假设您可以保证命令名中没有glob字符;如果这是真的,那么该检查非常便宜。)

但是,如果您打算将协同例程作为生成器工作,并且只在循环中使用,那么可以让它发出信号,表明它已直接完成。为此,请使其产生一个
中断

coroutine cor apply {{} {
    yield [info coroutine];  # A sensible result from [coroutine]
    yield 1
    yield 2
    yield 3
    return -code break
    # [tailcall break] would also work
}}

while true {
    puts [cor]
}
诀窍在于,你不会屈服于破发;您使用它作为协同程序的最终结果。(您以前的协同程序使用的是
收益率的结果,可能主要是出于运气。)


在写这篇文章时,我注意到了一个bug。运行协同程序的循环在8.6.8(我检查过的唯一版本)的顶层不起作用。不知道为什么。在过程/
apply
上下文中,这很好(在该上下文中,将协程名称作为参数传递是很自然的):

这些不同运行方式的字节码并没有明显不同。强制解释也可以使事情正常进行,这很好地表明这是一个真正的bug

set while while
$while true {
    puts [cor]
}

FWIW:
tailcall break
按预期适用于顶级案例(8.6.9)。
apply {c {
    while true {
        puts [$c]
    }
}} cor
set while while
$while true {
    puts [cor]
}