January 31, 2008

More on Python 2.5's generators

The implementation I proposed is actually flawed. No sooner than I wrote it, I noticed that the value returned after a send call doesn't depend on the value passed to send itself.

Why? Let me explain the situation. First, let's call the "sender" the function calling send, and "recipient" the function calling the yield.

The recipient's yield call is:

y <- yield x

Conversely, the sender's call is:

x <- send y

Can you see the point? x depends only on what happened in the receiver's past, so it can't depend on y, which is actually in the receiver's future. The same happens to the sender. So:

bar = do x <- yield 1
yield $ x+5

foo = do y1 <- send 1999
y2 <- send 100
return [y1,y2]

returns [1,2004]. That's not the way a Python 2.5's iterator works. Actually, such an iterator can't work at all!

If you can't believe this, try and run the equivalent piece of code in a Python 2.5 interpreter:

def bar():
x = (yield 1)
yield x+5

def foo():
it = bar()

y1 = it.send(1999)
y2 = it.send(100)

return [y1,y2]

You'll get the following error:

TypeError: can't send non-None value to a just-started generator

That simply means that you can't call send() if haven't previously called next(). That's exactly the same reason why my implementation was wrong: the semantics of send() says that the value returned by it must depend on the value passed to it. But, in the first yield() this semantics can't be fulfilled because the value passed to the yield depends only on the past in which, for the first call, can't include the value passed to send().

On subsequent calls, how can Python assure the semantics of send()? The answer is both easy and surprising: the value returned by send() depends on the next yield(), for which that value is actually in its past!

The solution I come up with is rewriting the send function and writing a next in this way:

next = do (RP (y,_)) <- get
return y

send x = do (RP (_,f)) <- get
let rp@(RP (y',f')) = f x
put rp
return y'

Now it works as expected. Notice that, surprisingly, the semantics of send/next depends only on send and next implementation: the yield function is completely apart from it.


deeksha said...

thus this version of software really tells about the more information about the new trend technologies.

php Training in Chennai