Updated 2013-02-11 02:20:31 by jbr

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

    tailcall 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
 #}