Awesome coroutine generators
Find a file
bjoli 00f5eca1c0 Update README.md
Fixe source colouring
2025-07-16 19:09:38 +00:00
awesome-coroutine-generators First commit. 2021-03-01 22:02:58 +01:00
README.md Update README.md 2025-07-16 19:09:38 +00:00

awesome-coroutine-generators

Welcome. Did you ever feel limited by the strict dogma of srfi-158 generators? Me neither. I just read Mark's thoughts about srfi-158 and thought I would implement them properly. This library is multi-way incompatible with srfi-158.

They allow you to write coroutine generators without having to deal with any nitty gritty details:

(import (awesome-coroutine-generators base))
(define simple-gen
  (simple-generator
    (let loop ((a 0))
      (when (< a 100)
        (yield a)
        (loop (+ a 1))))
    "Happy end!"))

;; We can now call a and it will yield the values 0 to 99.
(simple-gen) ;; => 0
(simple-gen) ;; => 1
...
(simple-gen) ;; => 99
(simple-gen) ;; => #<<generator-end> list-of-returned-values ("Happy end!")>

;; This looks very much like the coroutine-generators of srfi-158, but wait, there is more:

(define g
  (generator (a b)
    (let loop ((a a) (b b))
      (yield a)
      (loop b (+ a b)))))

;; prime the generator (if we use 1 1 it will generate the common fibonacci sequence)
(g 2 1)
;; Now it yields lucas numbers.
(g) ; => 2
(g) ; => 1
(g) ; => 3

;;
;; We can also pass values INTO the generator

(define g 
  (generator ()
    (let loop ((start (yield)))
      (when (>= start 0)
        (yield start)
        (loop (- start 1))))))
        
;; First, prime the generator. This is done to reach the point where it accepts
;; input:
(g)
;; Then we pass start into it:
(g 2)
(g) ; => 2
(g) ; => 1
(g) ; => 0
(g) ; <genertor-end>

;; We can also pass control over to another generator

(define generate-3-values
  (generator ()
    (let ((next (yield 1)))
      (yield next)
      (yield 'the-end))))
      
(define g
  (generator (g2)
    (yield-from g2)
    (yield "banana")))
    
(g generate-3-values)
(g) ;; => 1
(g 55) ; => 55
(g) ; => 'the-end
(g) ; => "banana"


Details

If you want to check whether the yield returned a value, wrap it in (maybe-none (yield val)) and test it with none?.

Licence

Public domain, or CC0. Whichever work best in your jurisdiction. If you build something from this, i'd be delighted to be mentioned by name.