accumulators

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Eugene Van den Bulke

    accumulators

    Hi,

    I have just finished reading Paul Graham Hackers & Painters book (which
    I recommend even though he seems a bit hard on Python)

    In chapter 13 of his book he wants to demonstrate LISP power VS other
    languages (to be precise he wants to illustrate what he means by
    relative power of programming language).

    "We want to write a function that generates accumulators - a function
    that takes a number n, and returns a function that takes another number
    i and returns n incremented by i (that's incremented by, not plus. An
    accumulator has to accumulate).

    In Common Lisp this would be:
    (defun foo (n)
    (lambda (i) (incf n i)))

    ....

    Python doesn't fully support lexical variables, you have to create a
    data structure to hold the value of n. And although Python does have a
    function data type, there is no literal representation for one (unless
    the body is only a single expression) so you need to create a named
    function to return. This is what you end up with:

    def foo(n):
    s=[n]
    def bar(i):
    s[0]+=i
    return s[0]
    return bar
    "

    It seems to me that this code does the job (but I am not sure I
    understand exactly what an accumulator is):

    def test(n):
    return lambda i: n+i

    Is that an accumulator? If it is, PG must have written this chapter
    working on an older verion of Python ...

    Regards,

    Eugene Van den Bulke
  • Paul Rubin

    #2
    Re: accumulators

    Eugene Van den Bulke <eugene@boardku lture.com> writes:[color=blue]
    > It seems to me that this code does the job (but I am not sure I
    > understand exactly what an accumulator is):
    >
    > def test(n):
    > return lambda i: n+i
    >
    > Is that an accumulator? If it is, PG must have written this chapter
    > working on an older verion of Python ...[/color]

    No. The idea of an accumulator is that whenever you call it, the
    internal state updates. That is, if accum(n) creates an accumulator,
    you should be able to say:

    a = accum(3) # create accumulator holding 3
    print accum(2) # prints "5"
    print accum(3) # prints "8"
    print accum(1) # prints "9"

    etc. The Pythonic way to do it is with a class instance:

    class accum:
    def __init__(self, n):
    self.s = n
    def __call__(self, i):
    self.s += i
    return self.s

    a = accum(3)
    (etc.)

    however, for programmers comfortable with the Lisp idioms of using
    internal lambdas, the class/object approach is cumbersome.

    Comment

    • Peter Otten

      #3
      Re: accumulators

      Paul Rubin wrote:
      [color=blue]
      > a = accum(3) # create accumulator holding 3
      > print accum(2) # prints "5"
      > print accum(3) # prints "8"
      > print accum(1) # prints "9"[/color]

      Should be

      a = accum(3) # create accumulator holding 3
      print a(2) # prints "5"
      print a(3) # prints "8"
      print a(1) # prints "9"

      Peter

      Comment

      • Paul Rubin

        #4
        Re: accumulators

        Peter Otten <__peter__@web. de> writes:[color=blue]
        > Should be
        >
        > a = accum(3) # create accumulator holding 3
        > print a(2) # prints "5"
        > print a(3) # prints "8"
        > print a(1) # prints "9"[/color]

        Oops, yes.

        Comment

        • Eugene Van den Bulke

          #5
          Re: accumulators

          Paul Rubin wrote:[color=blue]
          > Peter Otten <__peter__@web. de> writes:
          >[color=green]
          >>Should be
          >>
          >> a = accum(3) # create accumulator holding 3
          >> print a(2) # prints "5"
          >> print a(3) # prints "8"
          >> print a(1) # prints "9"[/color]
          >
          >
          > Oops, yes.[/color]

          thank you !!!

          Comment

          • Leif K-Brooks

            #6
            Re: accumulators

            Paul Rubin wrote:[color=blue]
            > class accum:
            > def __init__(self, n):
            > self.s = n
            > def __call__(self, i):
            > self.s += i
            > return self.s[/color]

            Just for fun, a full-blown class with documentation and the like:

            class Accumulator(obj ect):
            """This class implements a simple accumulator. Instate it with a
            starting value, or it will default to 0. It can be called with
            another value, which will be accumulated. The current value will
            also be returned.

            Example:
            [color=blue][color=green][color=darkred]
            >>> a = Accumulator(1)
            >>> a(2)[/color][/color][/color]
            3[color=blue][color=green][color=darkred]
            >>> a(1)[/color][/color][/color]
            4[color=blue][color=green][color=darkred]
            >>> a(3)[/color][/color][/color]
            7
            """

            __slots__ = '_value'

            def __init__(self, value=0):
            self._value = value

            def __call__(self, value):
            self._value += value
            return self._value

            def __str__(self):
            return str(self._value )

            def __repr__(self):
            return "<Accumulat or object with value %s>" % self._value

            Comment

            • Michele Simionato

              #7
              Re: accumulators

              Leif K-Brooks <eurleif@ecritt ers.biz> wrote in message news:<j3Nyc.333 5$Hf.1868685@ne wshog.newsread. com>...[color=blue]
              > Just for fun, a full-blown class with documentation and the like:
              >
              > class Accumulator(obj ect):
              > """This class implements a simple accumulator. Instate it with a
              > starting value, or it will default to 0. It can be called with
              > another value, which will be accumulated. The current value will
              > also be returned.
              >
              > Example:
              >[color=green][color=darkred]
              > >>> a = Accumulator(1)
              > >>> a(2)[/color][/color]
              > 3[color=green][color=darkred]
              > >>> a(1)[/color][/color]
              > 4[color=green][color=darkred]
              > >>> a(3)[/color][/color]
              > 7
              > """
              >
              > __slots__ = '_value'
              >
              > def __init__(self, value=0):
              > self._value = value
              >
              > def __call__(self, value):
              > self._value += value
              > return self._value
              >
              > def __str__(self):
              > return str(self._value )
              >
              > def __repr__(self):
              > return "<Accumulat or object with value %s>" % self._value[/color]

              I just don't see the need to use __slots__ here. The first rule about __slots__
              is: don't use them! OTOH the second rule (for expert only) is: don't use them!!

              That's true for any optimization, isnt'it? ;)

              Michele Simionato

              Comment

              • Scott David Daniels

                #8
                Re: accumulators

                Paul Rubin wrote:
                [color=blue]
                > ... The Pythonic way to do it is with a class instance:
                >
                > class accum:
                > def __init__(self, n):
                > self.s = n
                > def __call__(self, i):
                > self.s += i
                > return self.s
                >
                > a = accum(3)
                > (etc.)
                >
                > however, for programmers comfortable with the Lisp idioms of using
                > internal lambdas, the class/object approach is cumbersome.[/color]

                The way I'd do it is:

                class accum:
                def __init__(self, start):
                self.runningtot al = start

                def increment(self, value):
                self.runningtot al += value
                return self.runningtot al

                a = accum(3).increm ent
                Then you can use:
                a(3) ...

                That is, avoid magic names unless needed, and make the names obvious.

                --
                -Scott David Daniels
                Scott.Daniels@A cm.Org

                Comment

                Working...