I wouldn't use yield at all in Lisp/Scheme.
'yield' requires some kind of co-routine or continuation facility in the language. Many uses of yield can be implemented in a simpler functional way.
YIELD is basically related to the famous COME-FROM operator. ;-) Here, a call in some place can lead to different places in some other routine, depending on its execution context. So a routine suddenly has multiple entry points whose order is determined at runtime. For simple uses this may be fine, but I would argue that for more complex code reasoning about the code would get harder.
Take the Scheme example linked in the question:
(define/y (step)
(yield 1)
(yield 2)
(yield 3)
'finished)
(list (step) (step) (step))
Calling (step) multiple times returns different values then.
I would just create a closure:
(define step
(let ((state '(1 2 3 finished)))
(lambda ()
(pop state))))
This breaks above function with a yield into two different things: a variable that carries the state and a simple function that changes the state. The state is no longer implicitly coded into the execution sequence.
(list (step) (step) (step))))
One can imagine similar solutions for other uses of yield.
Compare that with the generators from the Common Lisp SERIES library:
(let ((x (generator (scan '(1 2 3 finished)))))
(list (next-in x)
(next-in x)
(next-in x)))
If we look at this Python example from another answer
def simpleRange(n):
for i in xrange(n):
yield i
for n in simpleRange(5):
print(n)
we can see that it duplicates the control structure. Both the calling place and the generator use a FOR iteration control structure. Using closures, we can get rid of the use of control structures inside the generator, by only providing the state transition code.