[Python-3000] genexp syntax for reduce

Boris Borcic bborcic at gmail.com
Wed Apr 19 18:30:35 CEST 2006


Guido van Rossum wrote:

> I wouldn't recommend this approach to anyone.

What about a variation ? It's arguably a 2.5a1 bug that yield expressions are 
permitted in generator expressions, but this suggests a slight syntax extension. 
Suppose

wrapper(<EXPR> for <VARS> after <SEEDEXPR> <MORECLAUSES>)

would mean what can in 2.5a1 be clumsily written as

wrapper(<EXPR> for _sd in (<SEEDEXPR>,) for <VARS> in (yield _sd) <MORECLAUSES>)

then, provided adequate wrapper definitions - I'll provide below - one could write

 >>> fixpoint(sqrt(x+1) for x after 2) # golden ratio is attractive fixed point
1.6180339887727981

 >>> fibo = seedbackloop(x+y for x,y after (1,1))

 >>> first10 = lambda gen : tuple(itertools.islice(gen,10))

 >>> first10(fibo)
(1, 1, 2, 3, 5, 8, 13, 21, 34, 55)

 >>> superfibo = seedbackloop(sum(trio) for trio after (1,1,1))

 >>> first10(superfibo)
(1, 1, 1, 3, 5, 9, 17, 31, 57, 105)

 >>> data = "put something intelligent here".split()

 >>> seedfold(pair for pair after ("Now please",data))
(((('Now please','put'),'something'),'intelligent'),'here')

 >>> seedfold([y,x] for x,y after ("Now please",data))
['here',['intelligent',['something',['put','Now please']]]]


Here for proof-of-concept definitions of the wrappers (without attention to 
corner cases/error messages, but tested with the above examples through the 
2.5a1 equivalent syntax)

def seedfold(gen) :
     from itertools import repeat
     feedback,source = gen.next()
     source = iter(source)
     next = source.next()
     feedback = gen.send((feedback,next) for _ in repeat(None))
     for next in source :
         feedback = gen.next()
     return feedback

def seedbackloop(gen) :
     from collections import deque
     from itertools import repeat
     feedback = deque(gen.next())
     for item in feedback :
         yield item
     feedback.append(gen.send(tuple(feedback) for _ in repeat(None)))
     while True :
         feedback.popleft()
         yield feedback[-1]
         feedback.append(gen.next())

def fixpoint(gen,maxiter=1000,eps=1e-10) :
     from itertools import repeat
     cnt = maxiter
     anterior = gen.next()
     posterior = gen.send(anterior for _ in repeat(None))
     while abs(posterior-anterior)>eps :
         cnt -= 1
         if cnt == 0 :
             raise ValueError("Expression did not converge after "
                              + str(maxiter) + " iterations")
         anterior = posterior
         posterior = gen.next()
     return posterior


Regards, Boris Borcic
--
assert "304" in "340343", "P4R4D15E M15M47C8"



More information about the Python-3000 mailing list