[jbr] 2013-02-09 - Here is some minimal sugar for defining and using generators with [coroutine] and [yield]. ====== # Use this instead of proc to create an iterator # proc iterator { name args body } { proc $name $args [subst { yield $body return -code break }] } # Call a proc which yields on each value and finally # calls [return -code break]. # proc iternext {} { return coco[incr ::iternext] } proc iterate { args } { set body [lindex $args end] set args [lrange $args 0 end-1] foreach { var iterator } $args { set cmd [iternext] uplevel "coroutine $cmd $iterator" if { [llength $var] > 1 } { lappend iters "foreach { $var } \[$cmd] { break }" } else { lappend iters "set $var \[$cmd]" } } uplevel [subst { while 1 { [join $iters \n] $body } }] } # An example # iterator iota-iter { n { m {} } } { if { $m eq {} } { set m $n set n 0 } for { set i $n } { $i < $m } { incr i } { yield $i } } #iterate n { iota-iter 10 } { # puts $n #} ====== <> Example