delay and force in Python

Dave Benjamin dave.benjamin at gmail.com
Wed Jan 19 16:50:33 CET 2005


Will Stuyvesant wrote:
> . def delay(exp): return lambda: exp

If you look at the definition of "delay" in SICP, you'll notice that 
it's defined as "syntax sugar", in other words, a macro. Since Python 
does not have macros, you'll have to just use "lambda", because by 
defining "delay" as a function, you're forcing the expression "exp" to 
evaluate immediately. In other words, theres a crucial difference between::

   delay(sys.stdout.write('evaluated\n'))

and::

   lambda: sys.stdout.write('evaluated\n')

If you type in those two snippets, you'll see what I mean.

Coincidentally, I attempted a similar experiment just a couple of days 
ago, and here's what I came up with::

    # Stream.py - Stream class inspired by SICP

     class Stream(object):
         pass

     class EndOfStream(Exception):
         pass

     class Item(Stream):
         def __init__(self, current, nextf):
             self.current = current
             self.nextf = nextf

         next = property(lambda self: self.nextf())

         def fold(self, f, init):
             return f(self.current, self.next.fold(f, init))

         def __getitem__(self, n):
             if n == 0:
                 return self.current
             else:
                 return self.next[n - 1]

         def __str__(self):
             return '<Stream.Item: %s, ...>' % self.current
         __repr__ = __str__

     class End(Stream):
         def fold(self, f, init):
             return init

         def __getitem__(self, n):
             raise EndOfStream()

         def _fail(self):
             raise EndOfStream()

         current = property(_fail)
         next = property(_fail)

         def __str__(self):
             return '<Stream.End>'
         __repr__ = __str__

Here's how it works::

     Python 2.4 (#1, Dec  4 2004, 20:10:33)
     [GCC 3.3.3 (cygwin special)] on cygwin
     Type "help", "copyright", "credits" or "license" for more information.
     >>> import Stream
     >>> s = Stream.Item(1, lambda: Stream.Item(2, lambda: Stream.End()))
     >>> s
     <Stream.Item: 1, ...>
     >>> s.current
     1
     >>> s.next
     <Stream.Item: 2, ...>
     >>> s.next.current
     2
     >>> s.next.next
     <Stream.End>
     >>> s.next.next.next
     Traceback (most recent call last):
       File "<stdin>", line 1, in ?
       File "Stream.py", line 37, in _fail
         raise EndOfStream()
     Stream.EndOfStream
     >>> def evens(n=0):
     ...     return Stream.Item(n, lambda: evens(n + 2))
     ...
     >>> s = evens()
     >>> s.current
     0
     >>> s.next.current
     2
     >>> s.next.next.current
     4

I don't know if this is useful or not, but it was an interesting 
exercise nonetheless.

Dave



More information about the Python-list mailing list