
I found this code on my hdd. I wrote it while drunk, and I don't remember writing it. When I tried to extend it, I broke a lot of things but now I brought it back to basic. I believe it works.
2.3 KiB
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
(yield ...) returns a "none"-value if no values are passed into the generator. You can test for it by using the none? procedure. Doing anything with this value unless testing if it is returned from yield is stupid.
Make it better?
I would prefer to have an API more like python and make it possible to be more explicit about when you pass values in or out. This works though.
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.