lazy function calling?
Robin Becker
robin at jessikat.demon.co.uk
Mon Oct 11 12:34:22 EDT 1999
In article <380202B7.ADF0E803 at GermanLloyd.org>, Berthold Hoellmann <hoel at GermanLloyd.org> writes
>Hello,
>
>I think I can remember a Python extension module, posted or announced
>here a while ago, where it was possible to make functions callable lazy.
>This means I could call a function spam just writing spam instead of
>spam(). Was I just dreaming or is it real. And if it's real, where can I
>get it :-)?
>
>Thanks
>
>Berthold
From: Joe Bowbeer <joeb at go2net.com> displayed some stuff based on lazy streams I think his
python implementation of
Structure and Interpretation of Computer Programs
Abelson and Sussman
http://mitpress.mit.edu/sicp/
I saved this with some hacks to memoized things
#From: Joe Bowbeer <joeb at go2net.com>
#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
return head(s)
def printStream(s, n): # print first n elements of stream s
while n > 0:
print head(s),
s, n = tail(s), n-1
print
def mapStream(f,s):
return (apply(f,[head(s)]), lambda f=f, s=s: mapStream(f,tail(s)))
#Now things start to get interesting:
# print 10 from an infinite stream of ones
ones = (1, lambda : ones)
printStream(ones, 10)
def addStreams(si, sj): # add corres. elements of two streams
if not si: return sj
if not sj: return si
tailsum = lambda ti=si, tj=sj : addStreams(tail(ti), tail(tj))
return (head(si) + head(sj), tailsum)
# infinitely many integers
integers = (0, lambda : addStreams(ones, integers))
printStream(integers, 10)
# infinite stream of Fibonacci numbers
fibs = (0, lambda : (1, lambda : addStreams(tail(fibs), fibs)))
printStream(fibs, 10)
# 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()
def addStreams(si, sj): # add corres. elements of two streams
if not si: return sj
if not sj: return si
return (head(si) + head(sj), Memo(lambda ti=si, tj=sj : addStreams(tail(ti), tail(tj))))
ones = (1, Memo(lambda : ones))
printStream(ones, 10)
# infinitely many integers
integers = (0, Memo(lambda : addStreams(ones, integers)))
printStream(integers, 10)
# infinite stream of Fibonacci numbers
fibs = (0, Memo(lambda : (1, Memo(lambda : addStreams(tail(fibs), fibs)))))
printStream(fibs, 10)
#----
#*SICP:
# Structure and Interpretation of Computer Programs
# Abelson and Sussman
# http://mitpress.mit.edu/sicp/
#----
#Joe Bowbeer
--
Robin Becker
More information about the Python-list
mailing list