Similar to range
but returns a generator instead of an array.
(defn iota [n]
(generate [i :range [0 n]] i))
(values (iota 3)) # => @[0 1 2]
Given multiple generators, zip
returns a generator that yields arrays
with one value from each input generator. It stops when on of the inputs is out
of elements.
(defn zip
[& rest]
(fiber/new
(fn []
(var k (map next rest))
(while (every? k)
(yield (seq [i :range [0 (length rest)]]
(in (in rest i) (in k i))))
(set k (seq [i :range [0 (length rest)]]
(next (in rest i) (in k i))))))))
(values (zip ["a" "b" "c"] (iota 100))) # => @[0 1 2] @[@["a" 0] @["b" 1] @["c" 2]]
# Note: `map` can be used in a similar way, as long as one of the arguments is
# not an infinite generator
(map tuple ["a" "b" "c"] (iota 100)) # => @[("a" 0) ("b" 1) ("c" 2)]
(defn window [n ds]
(fiber-fn :yi []
(var k (next ds))
(var win @[])
(loop [:repeat n]
(array/push win (in ds k))
(set k (next ds k)))
(yield win)
(while (not= k nil)
(set win (array/slice win 1))
(array/push win (in ds k))
(yield win)
(set k (next ds k)))
win))
(values (window 3 (iota 5))) # => @[@[0 1 2] @[1 2 3] @[2 3 4]]
(defn chain
"Chain multiple fibers or data structures together"
[& fbrs]
(coro
(loop [fb :in fbrs]
(var k (next fb))
(while (not= k nil)
(yield (in fb k))
(set k (next fb k))))))