1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
|
'\"
'\" Copyright (c) 2009 Donal K. Fellows.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH coroutine n 8.6 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
coroutine, yield, yieldto, coroinject, coroprobe \- Create and produce values from coroutines
.SH SYNOPSIS
.nf
\fBcoroutine \fIname command\fR ?\fIarg...\fR?
\fByield\fR ?\fIvalue\fR?
\fByieldto\fI command\fR ?\fIarg...\fR?
\fIname\fR ?\fIvalue...\fR?
.VS "8.7, TIP383"
\fBcoroinject \fIcoroName command\fR ?\fIarg...\fR?
\fBcoroprobe \fIcoroName command\fR ?\fIarg...\fR?
.VE "8.7, TIP383"
.fi
.BE
.SH DESCRIPTION
.PP
The \fBcoroutine\fR command creates a new coroutine context (with associated
command) named \fIname\fR and executes that context by calling \fIcommand\fR,
passing in the other remaining arguments without further interpretation. Once
\fIcommand\fR returns normally or with an exception (e.g., an error) the
coroutine context \fIname\fR is deleted.
.PP
Within the context, values may be generated as results by using the
\fByield\fR command; if no \fIvalue\fR is supplied, the empty string is used.
When that is called, the context will suspend execution and the
\fBcoroutine\fR command will return the argument to \fByield\fR. The execution
of the context can then be resumed by calling the context command, optionally
passing in the \fIsingle\fR value to use as the result of the \fByield\fR call
that caused
the context to be suspended. If the coroutine context never yields and instead
returns conventionally, the result of the \fBcoroutine\fR command will be the
result of the evaluation of the context.
.PP
The coroutine may also suspend its execution by use of the \fByieldto\fR
command, which instead of returning, cedes execution to some command called
\fIcommand\fR (resolved in the context of the coroutine) and to which \fIany
number\fR of arguments may be passed. Since every coroutine has a context
command, \fByieldto\fR can be used to transfer control directly from one
coroutine to another (this is only advisable if the two coroutines are
expecting this to happen) but \fIany\fR command may be the target. If a
coroutine is suspended by this mechanism, the coroutine processing can be
resumed by calling the context command optionally passing in an arbitrary
number of arguments. The return value of the \fByieldto\fR call will be the
list of arguments passed to the context command; it is up to the caller to
decide what to do with those values.
.PP
The recommended way of writing a version of \fByield\fR that allows resumption
with multiple arguments is by using \fByieldto\fR and the \fBreturn\fR
command, like this:
.PP
.CS
proc yieldMultiple {value} {
tailcall \fByieldto\fR string cat $value
}
.CE
.PP
The coroutine can also be deleted by destroying the command \fIname\fR, and
the name of the current coroutine can be retrieved by using
\fBinfo coroutine\fR.
If there are deletion traces on variables in the coroutine's
implementation, they will fire at the point when the coroutine is explicitly
deleted (or, naturally, if the command returns conventionally).
.PP
At the point when \fIcommand\fR is called, the current namespace will be the
global namespace and there will be no stack frames above it (in the sense of
\fBupvar\fR and \fBuplevel\fR). However, which command to call will be
determined in the namespace that the \fBcoroutine\fR command was called from.
.PP
.VS "8.7, TIP383"
A suspended coroutine (i.e., one that has \fByield\fRed or \fByieldto\fR-d)
may have its state inspected (or modified) at that point by using
\fBcoroprobe\fR to run a command at the point where the coroutine is at. The
command takes the name of the coroutine to run the command in, \fIcoroName\fR,
and the name of a command (any any arguments it requires) to immediately run
at that point. The result of that command is the result of the \fBcoroprobe\fR
command, and the gross state of the coroutine remains the same afterwards
(i.e., the coroutine is still expecting the results of a \fByield\fR or
\fByieldto\fR as before) though variables may have been changed.
.PP
Similarly, the \fBcoroinject\fR command may be used to place a command to be
run inside a suspended coroutine (when it is resumed) to process arguments,
with quite a bit of similarity to \fBcoroprobe\fR. However, with
\fBcoroinject\fR there are several key differences:
.VE "8.7, TIP383"
.IP \(bu
.VS "8.7, TIP383"
The coroutine is not immediately resumed after the injection has been done. A
consequence of this is that multiple injections may be done before the
coroutine is resumed. The injected commands are performed in \fIreverse
order of definition\fR (that is, they are internally stored on a stack).
.VE "8.7, TIP383"
.IP \(bu
.VS "8.7, TIP383"
An additional two arguments are appended to the list of arguments to be run
(that is, the \fIcommand\fR and its \fIargs\fR are extended by two elements).
The first is the name of the command that suspended the coroutine (\fByield\fR
or \fByieldto\fR), and the second is the argument (or list of arguments, in
the case of \fByieldto\fR) that is the current resumption value.
.VE "8.7, TIP383"
.IP \(bu
.VS "8.7, TIP383"
The result of the injected command is used as the result of the \fByield\fR or
\fByieldto\fR that caused the coroutine to become suspended. Where there are
multiple injected commands, the result of one becomes the resumption value
processed by the next.
.PP
The injection is a one-off. It is not retained once it has been executed. It
may \fByield\fR or \fByieldto\fR as part of its execution.
.PP
Note that running coroutines may be neither probed nor injected; the
operations may only be applied to coroutines that are suspended. (If a
coroutine is running then any introspection code would be merely inspecting
the state of where it is currently running; \fBcoroinject\fR/\fBcoroprobe\fR
are unnecessary in that case.)
.VE "8.7, TIP383"
.SH EXAMPLES
.PP
This example shows a coroutine that will produce an infinite sequence of
even values, and a loop that consumes the first ten of them.
.PP
.CS
proc allNumbers {} {
\fByield\fR
set i 0
while 1 {
\fByield\fR $i
incr i 2
}
}
\fBcoroutine\fR nextNumber allNumbers
for {set i 0} {$i < 10} {incr i} {
puts "received [\fInextNumber\fR]"
}
rename nextNumber {}
.CE
.PP
In this example, the coroutine acts to add up the arguments passed to it.
.PP
.CS
\fBcoroutine\fR accumulator apply {{} {
set x 0
while 1 {
incr x [\fByield\fR $x]
}
}}
for {set i 0} {$i < 10} {incr i} {
puts "$i -> [\fIaccumulator\fR $i]"
}
.CE
.PP
This example demonstrates the use of coroutines to implement the classic Sieve
of Eratosthenes algorithm for finding prime numbers. Note the creation of
coroutines inside a coroutine.
.PP
.CS
proc filterByFactor {source n} {
\fByield\fR [info coroutine]
while 1 {
set x [\fI$source\fR]
if {$x % $n} {
\fByield\fR $x
}
}
}
\fBcoroutine\fR allNumbers apply {{} {while 1 {\fByield\fR [incr x]}}}
\fBcoroutine\fR eratosthenes apply {c {
\fByield\fR
while 1 {
set n [\fI$c\fR]
\fByield\fR $n
set c [\fBcoroutine\fR prime$n filterByFactor $c $n]
}
}} allNumbers
for {set i 1} {$i <= 20} {incr i} {
puts "prime#$i = [\fIeratosthenes\fR]"
}
.CE
.PP
This example shows how a value can be passed around a group of three
coroutines that yield to each other:
.PP
.CS
proc juggler {name target {value ""}} {
if {$value eq ""} {
set value [\fByield\fR [info coroutine]]
}
while {$value ne ""} {
puts "$name : $value"
set value [string range $value 0 end-1]
lassign [\fByieldto\fI $target\fR $value] value
}
}
\fBcoroutine\fR j1 juggler Larry [
\fBcoroutine\fR j2 juggler Curly [
\fBcoroutine\fR j3 juggler Moe j1]] "Nyuck!Nyuck!Nyuck!"
.CE
.PP
.VS "8.7, TIP383"
This example shows a simple coroutine that collects non-empty values and
returns a list of them when not given an argument. It also shows how we can
look inside the coroutine to find out what it is doing, and how we can modify
the input on a one-off basis.
.PP
.CS
proc collectorImpl {} {
set me [info coroutine]
set accumulator {}
for {set val [\fByield\fR $me]} {$val ne ""} {set val [\fByield\fR]} {
lappend accumulator $val
}
return $accumulator
}
\fBcoroutine\fR collect collectorImpl
\fIcollect\fR 123
\fIcollect\fR "abc def"
\fIcollect\fR 456
puts [\fBcoroprobe \fIcollect\fR set accumulator]
# ==> 123 {abc def} 456
\fIcollect\fR "pqr"
\fBcoroinject \fIcollect\fR apply {{type value} {
puts "Received '$value' at a $type in [info coroutine]"
return [string toupper $value]
}}
\fIcollect\fR rst
# ==> Received 'rst' at a yield in ::collect
\fIcollect\fR xyz
puts [\fIcollect\fR]
# ==> 123 {abc def} 456 pqr RST xyz
.CE
.VE "8.7, TIP383"
.SS "DETAILED SEMANTICS"
.PP
This example demonstrates that coroutines start from the global namespace, and
that \fIcommand\fR resolution happens before the coroutine stack is created.
.PP
.CS
proc report {where level} {
# Where was the caller called from?
set ns [uplevel 2 {namespace current}]
\fByield\fR "made $where $level context=$ns name=[info coroutine]"
}
proc example {} {
report outer [info level]
}
namespace eval demo {
proc example {} {
report inner [info level]
}
proc makeExample {} {
puts "making from [info level]"
puts [\fBcoroutine\fR coroEg example]
}
makeExample
}
.CE
.PP
Which produces the output below. In particular, we can see that stack
manipulation has occurred (comparing the levels from the first and second
line) and that the parent level in the coroutine is the global namespace. We
can also see that coroutine names are local to the current namespace if not
qualified, and that coroutines may yield at depth (e.g., in called
procedures).
.PP
.CS
making from 2
made inner 1 context=:: name=::demo::coroEg
.CE
.SH "SEE ALSO"
apply(n), info(n), proc(n), return(n)
.SH KEYWORDS
coroutine, generator
'\" Local Variables:
'\" mode: nroff
'\" fill-column: 78
'\" End:
|