To @dmitry_vk answer about Common Lisp I would add that in Lisp, actually, generators are not really needed. Their use cases are fully covered by different applications of closures, special variables and macros - without the additional conceptual overhead of learning a new construct.
Sometimes even the built-in constructs will work. Let's look at the example from the Python wiki:
# add squares less than 100
from itertools import count, takewhile
sum = 0
square = (i*i for i in count())
bounded_squares = takewhile(lambda x: x < 100, square)
for i in bounded_squares:
sum += i
Using loop
it can be implemented in a much more straightforward manner:
CL-USER> (loop :for i :from 0 :while (< i 100) :sum (expt i 2))
328350
As loop
is much more versatile, than Python's for
there's no need to introduce special syntax here.
Let's consider another use case - iteration over some custom tree. Suppose the tree is represented by node
s pointing to their children
.
(defstruct node
data
children)
We can walk over any tree/subtree with a rather small and simple macro.
(defmacro dotree ((var root &optional result-form) &body body)
`(block nil
(labels ((traverse (node)
(let ((,var node))
,@body
(dolist (child (children node))
(traverse child))
,result-form)))
(when-it ,root
(traverse it)))))
(Warning: for the sake of more clarity I didn't use gensym
in it, but you should).
Here's the example of its usage - getting a list of all the leaf nodes:
(let (rez)
(dotree (node tree (reverse rez))
(when (leafp node)
(push node rez))))
This looks and works just like the standard dolist
macro. And, as with dolist
you can stop the iteration at any time, by calling return
.
Overall, I'm yet to see a practical example of generator usage that can't be implemented in Lisp in some less complex way.
P.S. You can also take a look at the SERIES Lisp library, that implemented a similar concept to generators in the 90's. Or CLAZY - from the late 2000's.