So I found an interesting paper describing how to use lazy lists to represent infinite series and i thought I’d try to do the same thing in python using generators, which are similar.
It’s cool but kind of a mess. I assume with more thought this could be tweaked into a clear thing. The thunking is especially gross. Maybe totally unnecessary? At some point I felt like it was the right thing to do for some reason and then I stuck with it.
The obvious simpler way would be to truncate the series at n=100 or something and just use lists. Why would I ever want terms higher than that anyhow? Interesting exercise though.
# lazy evaluation # sometimes a problem can be simple if we're working in an insanely huge space. # if you can proceed thorugh the space lazily, this might be an acceptable strategy # decorator to convert function into a function that returns a thunk that will evelauted to the original function def thunkify(func): def func_wrapper(*args, **kwargs): return lambda: func(*args, **kwargs) return func_wrapper #geometric series def geo(): while True: yield 1 #exponential expansion def exp(): num = 0. fact = 1. yield 1. while True: num += 1. fact = fact * num yield 1./fact @thunkify def const(c): yield c while True: yield 0 def oneX(): yield 0 yield 1 while True: yield 0 @thunkify def convertArray(myarray): for i in myarray: yield i while True: yield 0 # oneX = convertArray([0,1]) myexp = exp() print next(myexp) print next(myexp) print next(myexp) ''' #an old unthunked approach. I need to instantiate all generators before passing them. def add(a, b): while True: yield next(a) + next(b) mysum = add(oneX(), const(3)) print next(mysum) print next(mysum) print next(mysum) ''' #If i do this way, need to always returns thunks for all constructors. # such as const(3): def thunk @thunkify def add(a, b): #could this be lazier? # do I want egnerator combinators to instantiate the genereators? a = a() b = b() while True: yield next(a) + next(b) mysum = add(oneX, const(3)) mysum = mysum() print next(mysum) print next(mysum) print next(mysum) #I fear rethunking will lead to weird bugs. rehtunked guys might be linked to each other in ways you might not expect def rethunk(a): return lambda: a @thunkify def constmult(c, a): a = a() while True: yield c * next(a) @thunkify def mult(a,b): abar = a() bbar =b() a0 = next(abar) b0 = next(bbar) bbar = rethunk(bbar) abar = rethunk(abar) yield a0 * b0 remainprod = add(constmult(a0, bbar), mult(abar,b)) remainprod = remainprod() while True: yield next(remainprod) @thunkify def integrate(C, a): num = 0. a = a() yield C while True: num += 1. yield next(a)/num @thunkify def differentiate(a): a = a() num = 0. next(a) #toss away constant while True: num += 1. yield num * next(a) def evalseries(x, n, series): pass def take(n, gen): gen = gen() arr =  for i in range(n): arr.append(next(gen)) return arr print take(5, exp) print take(5, mult(oneX, exp)) print take(5, integrate(0,oneX)) print take(5, differentiate(oneX)) print take(5, differentiate(exp))