如何检测Tcl协程的完成?

时间:2019-01-20 04:31:17

标签: 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"
}

这有效,但感觉像是黑客,而且很脆。如果我重命名cor而忘记在陷阱中重命名它,它将失败。如果我将cor留在陷阱中,它将捕获无关的错别字。

必须有一个更好的方法。什么事?

1 个答案:

答案 0 :(得分:2)

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

while {[llength [info commands cor]]} {
    puts [cor]
}

但是,如果您打算将协程作为发生器工作并且仅在循环中使用,则可以使它指示直接完成。为此,请使其产生一个break

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]
}

诀窍是您不要 yield休息;您将其用作协程的最终结果。 (您的旧协程使用yield作为结果,可能主要是因为运气。)


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

apply {c {
    while true {
        puts [$c]
    }
}} cor

这些各种运行方式的字节码看起来没有明显不同。强制解释还可以使事情正常进行,这很棒表明这是一个真正的错误。

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