Normal thinking of the code is: OK, call gen1(), save the return value into a variable 'x' and call print(x); call gen1() again and do the same; cal gen1() again, again, again... In short, 'foreach' is a master and 'generator' is a slave - master calls slave while slave has a job to do.

But we can thing a little bit different: OK, we know what we are going to do with the generator's value - run the body of FOREACH form ((print x) in our case). So, it is possible to pass that code to a generator and the generator will call it when needed. The generator becomes a master and foreach becomes a slave. We can think about a generator as a normal function that receives additional parameter - what to do with the result value aka continuation. By pygen's macros the code above is transformed into something like this:

When to use

If a generator function is simple that means it is relatively easy to save and and restore the function's state in a closure it might be more appropriate to use series package or some other lazy-lists package. For someone it could be more convenient to pass a functional parameter represented a continuation to a generator directly.
Pygen is doing well when a generator function is a quite complex, e.g. there are several inner loops or when it is needed to work with 'unwind-protect' resources such as files. For example, SAX and pull XML parsers could be implemented using generators.

Conclusion

Generators are an abstraction. If it is suitable for you - pygen is here :)