Fibonacci numbers with coroutine

The following command emits one of the Fibonacci numbers, the next in the series, each time it is called.

proc f {} {
    yield [set a 0]
    yield [set b 1]
    while 1 {
        yield [incr a $b]
        lassign [list $b $a] a b
    }
}
coroutine fib f

The call to coroutine is considered to be fib(0) and returns 0. Add a nullary yield (or the customary yield [info coroutine]) before the first yield to make the first call to fib the zeroth call.

It's about six times slower than ::math::fibonacci, but it's hard to compare timing when the coroutine needs to be destroyed and reinstated during every iteration, and the call to fib wrapped in a for statement to advance the sequence.

Time by:

time {for {set i 0} {$i <= 46} {incr i} fib ; rename fib "" ; coroutine fib f} 100000  ;# relative 5.5
time {::math::fibonacci 46} 100000                                                     ;# relative 1.0

This command allows the Fibonacci series to be restarted if an argument is passed to fib:

proc f {} {
    yield
    while 1 {
        yield [set a 0]
        yield [set b 1]
        while {[yield [incr a $b]] eq {}} {
            lassign [list $b $a] a b
        }
    }
}
coroutine fib f

It is only slightly faster than the first command. Using this code and calling fib 46 times instead of using a loop makes this implementation about three times slower than ::math::fibonacci.

Time by:

time {for {set i 0} {$i <= 46} {incr i} fib ; fib stop} 100000 ;# relative 4.9
time {
    fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib
    fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib
    fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib
    fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib ; fib
    fib ; fib ; fib ; fib ; fib ; fib
    fib reset
} 100000                                                       ;# relative 3.1