# lambda fun: infinite streams

Joe Bowbeer joeb at go2net.com
Sat Aug 7 05:53:21 CEST 1999

```Fya.

I was doing a little investigating with Python's lambda expressions and
it looks like they are indeed powerful enough to create some of my
favorite beasts: infinitely long streams [*].

If we define a stream to be a 'pair' of the form (head, tail), where
head is the first element and tail is a function that returns the rest
of the stream (which is itself a stream), then we can define 'head' and
'tail' functions in Python as follows:

def head(s): # return first element in stream
return s and s[0]

def tail(s): # return remainder of stream
return s and s[1] and s[1]()

We create a new stream given a head element and a tail stream as
follows:

s = (head, lambda : tail)

# I'd use a 'special form' or macro above if Python had them..

Here are two more functions that operate on streams. (I'd implement
these tail-recursively if it were more efficient.)

def nthStream(s, n): # return nth element of stream s
while n > 0:
s, n = tail(s), n-1

def printStream(s, n): # print first n elements of stream s
while n > 0:
s, n = tail(s), n-1
print

Now things start to get interesting:

# infinite stream of ones
ones = (1, lambda : ones)

# print some ones
printStream(ones, 10)

if not si: return sj
if not sj: return si
tailsum = lambda ti=si, tj=sj : addStreams(tail(ti), tail(tj))

# infinitely many integers
integers = (0, lambda : addStreams(ones, integers))

# infinite stream of Fibonacci numbers
fibs = (0, lambda : (1, lambda : addStreams(tail(fibs), fibs)))

# Too bad 'int' can only represent a finite number of digits...

Better performance can be achieved by memo-izing the functions that
evaluate the tails. A simple Memo class can be defined as follows. It
lazily evaluates the 'thunk' function and then memorizes the result:

class Memo: # memoized call-by-need thunk
def __init__(self, thunk):
self.result, self.thunk = None, thunk
def eval(self):
if self.thunk:
self.result, self.thunk = self.thunk(), None
return self.result

Memo-ized streams are created as follows:

s = (head, Memo(lambda : tail))

And the tail function becomes:

def tail(s): # return remainder of stream
return s and s[1] and s[1].eval()

----
*SICP:

Structure and Interpretation of Computer Programs
Abelson and Sussman
http://mitpress.mit.edu/sicp/

----
Joe Bowbeer

```