I wrote several options. First you ask
(define (each-fib fn) (letrec ((next (lambda (ab) (fn a) (next b (+ ab))))) (next 0 1)))
can be written shorter. The template is used so often that a special named let syntax has been introduced. Your function looks like this using the name let:
(define (each-fib fn) (let next ([a 0] [b 1]) (fn a) (next b (+ ab))))
In order to control transferred from one function to another, you can use the style of continued transmission in languages with TCO support. Each function receives an additional argument, often called k (to continue). Function k is something to do next.
Using this style, you can write your program as follows:
(define (generate-fibs k) (let next ([a 0] [b 1] [kk]) (ka (lambda (k1) (next b (+ ab) k1))))) (define (count-down nk) (let loop ([nn] [fibs '()] [next generate-fibs]) (if (zero? n) (k fibs) (next (λ (a next) (loop (- n 1) (cons a fibs) next)))))) (count-down 5 values)
Now it’s a little annoying to write in style manually, so it can be convenient to enter cooperative routines. Violation of the rules for using set! I decided to use the generic fibs variable, in which generate-fibs repeatedly writes new fibonacci numbers. The count-down procedure simply reads the values when the countdown ends.
(define (make-coroutine co-body) (letrec ([state (lambda () (co-body resume))] [resume (lambda (other) (call/cc (lambda (here) (set! state here) (other))))]) (lambda () (state)))) (define fibs '()) (define generate-fib (make-coroutine (lambda (resume) (let next ([a 0] [b 1]) (set! fibs (cons a fibs)) (resume count-down) (next b (+ ab)))))) (define count-down (make-coroutine (lambda (resume) (let loop ([n 10]) (if (zero? n) fibs (begin (resume generate-fib) (loop (- n 1)))))))) (count-down)
And a bonus you will get a version with shared streams:
#lang racket (letrec ([result #f] [count-down (thread (λ () (let loop ([n 10] [fibs '()]) (if (zero? n) (set! result fibs) (loop (- n 1) (cons (thread-receive) fibs))))))] [produce-fibs (thread (λ () (let next ([a 0] [b 1]) (when (thread-running? count-down) (thread-send count-down a) (next b (+ ab))))))]) (thread-wait count-down) result)
The stream version is specific to Racket, others should work anywhere.