reduce() anomaly?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Terry Reedy

    Re: Python's simplicity philosophy


    "Alex Martelli" <aleax@aleax.it > wrote in message
    news:%N8tb.2827 7$hV.1041253@ne ws2.tin.it...[color=blue]
    > to be consistent with your other arguments, no doubt you'd argue for
    > a .sort() followed by [-1] as "more general" than max...[/color]

    By my definition of "more general", a function that returns all order
    statistics of a list is trivially more general than one that returns
    any fewer, including just one. It conveys a superset of the
    infomation conveyed by less general functions and answers a superset
    of the questions they answer. If you add a control parameter
    specifying which order statistics to return, then less general
    functions have a restriced domain.

    So I have no idea your intent in appearing to challenge this and how
    you think it contributes to your overall argument. Is your idea of
    'more general' so different?

    Terry J. Reedy



    Comment

    • Andrew Dalke

      Re: Python's simplicity philosophy

      Alex Martelli:[color=blue]
      > "added"? 'max' worked that way since well before I met Python. But
      > to be consistent with your other arguments, no doubt you'd argue for
      > a .sort() followed by [-1] as "more general" than max...[/color]

      Even better (tongue-in-cheek) would be a function to get the
      t largest (or s largest to t largest) without necessarily comparing
      between elements whose values are guaranteed out of range

      Just looked through Knuth for that. There are various ways
      listed, but no neat name to use for that function. :)
      Look under 'select k largest' and 'select kth largest'. Most
      of the hits are in the exercises. First one is for Hoare, and
      there's a reference to Dodgson (Carroll) and lawn tennis.

      Andrew
      dalke@dalkescie ntific.com


      Comment

      • Douglas Alan

        Re: Python's simplicity philosophy

        Dang Griffith <noemail@noemai l4u.com> writes:
        [color=blue][color=green]
        >> I would say that if you didn't get introduced to at least the concept
        >> of functional programming and a hint of how it works, then something
        >> was seriously wrong with your CS education.[/color][/color]
        [color=blue]
        > I've been lurking this thread for a while, but missed the beginning.
        > Can I ask where you got your CS education (school and year)? From
        > the conversation, it seems that right or wrong, your education
        > exceeds those in this group. Where should I send my children such
        > that they receive a better CS education that I?[/color]

        I took some sort of one-day class at the public library on BASIC when
        I was about 12. Then later in high school, I was handed a book on APL
        by a friend's father. Then my mother sent me off to Harvard Summer
        School, where I first took an official CS-101 class (and a class on
        Astronomy), and then I went to MIT for undergraduate school, where I
        also took their CS-101.

        So, in a way, I had four different CS-101's, and in *all* of them I
        was exposed to concepts of functional programming, except for the
        BASIC case.

        Despite me having studied at Harvard and MIT, it is my belief that you
        don't have to have attended either of these places to receive a decent
        CS education. You just have to be taught by people who don't think
        that something as simple as reduce() is beyond your abilities. In
        fact, perhaps it was in a small part because I was introduced to
        concepts such as reduce() at a young age that I was able to become
        smart enough to get into such a fine school. Would you deny such an
        opportunity to those who learn to program in Python?

        |>oug

        Comment

        • Dave Brueck

          Re: Python's simplicity philosophy

          > You just have to be taught by people who don't think[color=blue]
          > that something as simple as reduce() is beyond your abilities.[/color]

          Nobody in this entirely too-long thread has asserted such a thing. You have
          inferred from people saying that it's non-obvious or less readable than other
          constructs that they mean it's difficult to teach or that people are too stupid
          to learn it. Nothing could be farther from the truth.

          It's not that reduce is hard to learn - it's just that there are simpler and
          clearer constructs that do the same thing and are more readable to most people.
          That's it!
          [color=blue]
          > fact, perhaps it was in a small part because I was introduced to
          > concepts such as reduce() at a young age that I was able to become
          > smart enough to get into such a fine school. Would you deny such an
          > opportunity to those who learn to program in Python?[/color]

          <retching noises> Ok, I'm done with this thread. Have fun,
          Dave


          Comment

          • Douglas Alan

            Re: Python's simplicity philosophy

            "Dave Brueck" <dave@pythonapo crypha.com> writes:
            [color=blue][color=green]
            >> You just have to be taught by people who don't think
            >> that something as simple as reduce() is beyond your abilities.[/color][/color]
            [color=blue]
            > Nobody in this entirely too-long thread has asserted such a thing.[/color]

            There *have* been postings that have asserted that reduce() is
            difficult to learn. But it is not. I learned it when I was in high
            school with no trouble and no background. I've already posted a
            perfectly good description of reduce() that anyone should be able to
            learn in under a minute. And if despite this, someone finds reduce()
            difficult to learn, then perhaps this is particularly the kind of
            thing they that *should* be learning, so that such things will no
            longer be difficult for them.
            [color=blue]
            > You have inferred from people saying that it's non-obvious or less
            > readable than other constructs that they mean it's difficult to
            > teach or that people are too stupid to learn it. Nothing could be
            > farther from the truth.[/color]

            Neither is sum() obvious until you know what it does. Perhaps it is
            it just a synonym for add? Or maybe it produces summaries of some
            sort. What happens if you give it an empty list? In the time that
            you can answer these questions for yourself, you can have figured out
            the more general tool, reduce(), and once you have, then it is just as
            obvious and readable as sum(), only it has other uses as well.
            [color=blue]
            > It's not that reduce is hard to learn - it's just that there are
            > simpler and clearer constructs that do the same thing and are more
            > readable to most people. That's it![/color]

            Well, bah! There are precious few constructs in this world that are
            clearer and more readable than

            reduce(add, seq)

            |>oug

            Comment

            • BW Glitch

              Re: Python's simplicity philosophy

              Douglas Alan wrote:
              [color=blue]
              > BW Glitch <bwglitch@hotpo p.com> writes:
              >
              >[color=green][color=darkred]
              >>>The mantra "there should be only one obvious way to do it" apparently
              >>>implies that one should remove powerful, general features like
              >>>reduce() from the language, and clutter it up instead with lots of
              >>>specific, tailored features like overloaded sum() and max().[/color][/color]
              >
              >[color=green]
              >>That's not what _I_ understand. There's room for powerful features,
              >>but when these features gives trouble to the people who just want
              >>something done, then another approach should be taken.[/color]
              >
              >
              > If there's a problem with people not understaning how to sum numbers
              > with reduce(), then the problem is with the documentation, not with
              > reduce() and the documentation should be fixed. It is quite easy to
              > make this fix. Here it is:[/color]

              You are assuming way too much. Documentation is meant to clarify what a
              function does, not a tutorial on what a function is. That's why your
              CS101 professor should have taught you that the name of the function
              should state what the function does. sum() states clearly that it is
              meant to sum something (a connection is made with numbers, because
              that's what most people associate numbers). reduce(), OTOH, states
              nothing, it reduces. But what? Why should I care for a function that
              isn't clear?
              [color=blue]
              > FAQ
              > ---
              > Q: How do I sum a sequence of numbers?
              >
              > A: from operator import add
              > reduce(add, seq)
              >
              > Problem solved.
              >[/color]

              A: Guru.

              Q: How a user that reads the manual is called?

              ;)
              [color=blue][color=green]
              >>And I'm not talking about stupid people. I'm talking about the
              >>microbiolgi st/chemist/physics/etc who is programming because of
              >>need.[/color]
              >
              >
              > If a microbiologist cannot understand the above, they have no business
              > being a microbiologist.[/color]

              Why should he? Because he could care less about a function called
              reduce()? Because he just want to do his job, regardless on how a CS
              expert does it? Because he didn't learned LISP as his first language?
              [color=blue]
              >I learned reduce() in high school, and it
              > didn't take me any longer than the 60 seconds I claim it will take
              > anyone with a modicum of intelligence.[/color]

              Please, get your fact straights.

              Do you know that people learn in different ways? Just because you
              learned something one way doesn't mean everyone else should learn it
              (and understand it) the same way you do.
              [color=blue][color=green][color=darkred]
              >>>If so, clearly this mantra is harmful, and will ultimately result
              >>>in Python becoming a bloated language filled up with "one obvious
              >>>way" to solve every particular idiom. This would be very bad, and
              >>>make it less like Python and more like Perl.[/color][/color]
              >
              >[color=green]
              >>You feel ok? Perl's mantra is "More Than One Way To Do It"...[/color]
              >
              >
              > If both the mantras cause a language to have general features
              > replaced with a larger number of specialized features that accomplish
              > less, then both mantras are bad.
              >[/color]

              Mantras are cute names for design decisions (I know, mantras doesn't
              mean that, but in these context). When designing something, certain
              compromises must be made. Guido van Rossum (GvR or BDFL) made some
              decisions early on and have stayed with Python ever since. Good or bad,
              we have to stick with the decisions. Why? Because each decision
              represents a solution from many to a single problem. If we start making
              exceptions to the decision, the decision should be rethought. But more
              importantly, if it works, don't fix it.

              Unless you go by the engineering mantra...
              [color=blue][color=green][color=darkred]
              >>>I can already see what's going to happen with sum(): Ultimately,
              >>>people will realize that they may want to perform more general
              >>>types of sums, using alternate addition operations. (For intance,
              >>>there may be a number of different ways that you might add together
              >>>vectors -- e.g, city block geometry vs. normal geometry. Or you
              >>>may want to add together numbers using modular arithmetic, without
              >>>worrying about overflowing into bignums.) So, a new feature will
              >>>be added to sum() to allow an alternate summing function to be
              >>>passed into sum(). Then reduce() will have effectively been put
              >>>back into the language, only its name will have been changed, and
              >>>its interface will have been changed so that everyone who has taken
              >>>CS-101 and knows off the top of their head what reduce() is and
              >>>does, won't easily be able to find it.[/color][/color]
              >
              >[color=green]
              >>I don't get you. There's a reason why special functions can be
              >>overloaded (__init__, __cmp__, etc.; I don't use others very
              >>often). That would allow for this kind of special
              >>treatments. Besides GvR would not accept your scenario.[/color]
              >
              >
              > There are often multiple different ways to add together the same data
              > types, and you wouldn't want to have to define a new class for each
              > way of adding. For instance, you wouldn't want to have to define a
              > new integer class to support modular arithmetic -- you just want to
              > use a different addition operation.[/color]

              Define a class then. What you are describing is a specific case which
              most people don't face in everyday problems. If you have a set of tools,
              try to use the best combination for the given tool. If all you have is a
              hammer, everything start looking like a nail. ;) If you have to program
              in Java, everything start looking like a class.
              [color=blue][color=green]
              >>Also, whytf do you mention so much CS101?[/color]
              >
              >
              > Because anyone who has studied CS, which should include a significant
              > percentage of programmers, will know instantly where to look for the
              > summing function if it is called reduce(), but they won't necessarily
              > know to look for sum(), since languages don't generally have a
              > function called sum(). And everyone else will not know to look for
              > either, so they might as well learn a more powerful concept in the
              > extra 30 seconds it will take them.[/color]

              False. Programmers come from many sources. Restraining yourself to CS
              people is bad enough. As Alex Martelli mentioned in another post of this
              thread, power should be demonstrable. It's quite amusing that no one has
              showed an example of the power of reduce() (by itself, not its side
              effects).

              [snip][color=blue][color=green]
              >>IMHO, you think that the only people that should make software
              >>is a CS major.[/color]
              >
              >
              > Did I say that?[/color]

              You didn't. But I infere that from what you've said in this thread.
              [color=blue][color=green][color=darkred]
              >>>>>To me, there is never *one* obviously "right way" to do anything[/color][/color]
              >
              >[color=green][color=darkred]
              >>>>Never? I doubt this very much. When you want to add two numbers in a
              >>>>programmi ng language, what's your first impulse? Most likely it is
              >>>>to write "a + b".[/color][/color]
              >
              >[color=green][color=darkred]
              >>>Or b + a. Perhaps we should prevent that, since that makes two
              >>>obviously right ways to do it![/color][/color]
              >
              >[color=green]
              >>Even without any algebra, any kid can tell you that 1 + 2 is the same
              >>as 2 + 1. Replace 1 and 2 by a and b and you get the same result.[/color]
              >
              >
              > Yes, but they are still two *different* ways to to get to that result.
              > Starting with a and adding b to it, is not the same thing as starting
              > with b and adding a to it. It is only the commutative law of
              > arithmetic, as any good second grade student can tell you, that
              > guarantees that the result will be the same. On the other hand, not
              > all mathematical groups are albelian, and consequently, a + b != b + a
              > for all mathematical groups.
              >[/color]

              This might be the case IF we were talking about Matlab/Octave, which are
              languages design towards mathematics.

              This would be the case of concatenating strings ('Hello ' + 'World! ' <>
              'World! ' + 'Hello '), but you should expect that to happen.
              [color=blue][color=green][color=darkred]
              >>>C'mon -- all reduce() is is a generalized sum or product. What's
              >>>there to think about? It's as intuitive as can be. And taught in
              >>>every CS curiculum. What more does one want out of a function?
              >>>|>oug[/color][/color]
              >
              >[color=green]
              >>It wasn't obvious for me until later. reduce() is more likely to be
              >>used for optimization. IIRC, some said that optimization is the root
              >>of all evil.[/color]
              >
              >
              > I don't know what you are getting at about "optimizati on". Reduce()
              > exists for notational convenience--i.e., for certain tasks it is easer
              > to read, write, and understand code written using reduce() than it
              > would be for the corresponding loop--and understanding it is no more
              > difficult than understanding that a summing function might let you
              > specify the addition operation that you'd like to use, since that's
              > all that reduce() is![/color]

              Optimization was from somenone else in the thread whom I might
              misunderstood.

              It's still not obvious. You need to understand 1) whattf does reduce()
              do and how, 2) what does the function passed does and 3) what the array
              is about.
              [color=blue][color=green]
              >>Just because it's _obvious_ to you, it doesn't mean it's obvious to
              >>people who self taught programming.[/color]
              >
              >
              > It was obvious to me when I was self-taught and I taught myself APL in
              > high-school. It also seemed obvious enough to all the physicists who
              > used APL at the lab where I was allowed to hang out to teach myself
              > APL.[/color]

              Well, I learned TI-BASIC, C, C++ and then went on to learn Scheme,
              Prolog and Python. Most of these during the last 6 years. Have I missed
              something because I didn't know how to use reduce()? No. And more
              importantly, what is a real life scenario where I should go with
              reduce() instead of a loop? From what you've said, the only reason to
              use reduce() is to show mere mortals that I know how to use reduce().
              Besides that, Martelli have pointed that it provides no advantage what
              so ever. And readability suffers because of the high abuse of this function.

              --
              Andres Rosado

              -----BEGIN TF FAN CODE BLOCK-----
              G+++ G1 G2+ BW++++ MW++ BM+ Rid+ Arm-- FR+ FW-
              #3 D+ ADA N++ W OQP MUSH- BC- CN++ OM P75
              -----END TF FAN CODE BLOCK-----

              A plague upon all their houses!
              -- Scourge (BW)

              Comment

              • Rainer Deyke

                Re: Python's simplicity philosophy

                Douglas Alan wrote:[color=blue]
                > Q: How do I sum a sequence of numbers?[/color]

                In three lines:

                x = 0
                for element in seq:
                x += element

                In two lines:
                [color=blue]
                > A: from operator import add
                > reduce(add, seq)[/color]

                Unless seq is empty, in which case you need this:

                from operator import add
                reduce(add, seq, 0)

                In one line:

                x = sum(seq)


                And that is why 'sum' is a worthwhile part of the Python standard library
                and 'reduce' is not: using 'sum' is significantly shorter than using a for
                loop, while using 'reduce' is not.


                --
                Rainer Deyke - rainerd@eldwood .com - http://eldwood.com


                Comment

                • Douglas Alan

                  Re: Python's simplicity philosophy

                  Alex Martelli <aleax@aleax.it > writes:
                  [color=blue]
                  > But to be consistent with your other arguments, no doubt you'd argue
                  > for a .sort() followed by [-1] as "more general" than max...[/color]

                  That would have a larger big O time growth value -- most likely
                  O(n * log n) vs. O(n), for reasonable implemenations. And while I
                  wouldn't sweat a factor of 2 for a feature of a RAD or scripting
                  language, I would be more concerned about moving to a larger big O
                  value.
                  [color=blue][color=green]
                  >> Well, perhaps you can explain your confusion to me? What could
                  >> possibly be unintuitive about a function that is just like sum(),
                  >> yet it allows you to specify the addition operation that you want
                  >> to use?[/color][/color]
                  [color=blue]
                  > Addition, as you have remarked elsewhere, is intrinsically suitable
                  > for being applied to multiple operands; one is therefore naturally
                  > disposed to think in terms of "add them all up", "sum them all", and
                  > the like, NOT in terms of "iterativel y perform[/color]
                  [color=blue]
                  > total = operator.add(to tal, item)[/color]
                  [color=blue]
                  > for all items in the sequence of numbers". But, reduce as it exists
                  > in Python today cannot be clearly defined EXCEPT by such an
                  > iteration with some generic "callable which accepts two arguments"
                  > specified in lieu of the operator.add. Given this total generality,
                  > even though hardly ever does it make sense to USE it, reduce becomes
                  > quite complex.[/color]

                  Your proposed extension to max() and min() has all the same problems.
                  But reasonable programmers don't abuse this generality, and so there
                  is little reason for the reasonable programmer to devote any
                  head-space to it. A programming language should be made to make life
                  as easy as possible for the reasonable programmer. Not to assume that
                  all programmers are latent unreasonable programmers and try to force
                  this urge to be stiffled. Don't take my word for it -- ask Paul
                  Graham. I believe he was even invited to give the Keynote Address at
                  a recent PyCon.

                  A tutorial for new programmers doesn't have to go into any of the
                  nuances of how one might abuse reduce() because that's not what
                  tutorials are for. It can merely say that reduce() is for applying a
                  binary operation such as "+" or "*" to a sequence of numbers, give a
                  couple examples on how to do it, and leave it at that. If the student
                  comes to a point where they want or need to know more details, they
                  can check the reference manual or experiment with it.
                  [color=blue]
                  > You've even argued in this thread, incorrectly, that reduce could be
                  > eliminated if only all binary operators were able to accept arbitrary
                  > numbers of arguments. This, plus your insistence that 'reduce' is
                  > "just like" APL's / (which does NOT accept arbitrary functions on its
                  > left -- just specific operators such as +), indicate a _misconception_
                  > of reduce on your part. I'm sure you don't hold it consciously, but
                  > these miscommunicatio ns indicate that even you, reduce's paladin, do
                  > NOT properly grasp reduce "intuitivel y".[/color]

                  Just what is it that I don't grasp again? I think my position is
                  clear: I have no intention to abuse reduce(), so I don't worry myself
                  with ways in which I might be tempted to.
                  [color=blue]
                  > Having (e.g.) add accept a sequence argument (like max does), or, for
                  > explicitness and potentially performance, grow an add.reduce attribute
                  > just like in Numeric, would give no particular problems. I'd still
                  > want (just like Numeric does) to have sum as a name for add.reduce,
                  > because it's by far the most common case[/color]

                  So, now you *do* want multiple obviously right ways to do the same
                  thing?
                  [color=blue]
                  > and avoids getting into the issue of what the (expletive delete)
                  > does "reducing" have to do with anything that "add.reduce " does
                  > (it's really a curve ball compared with the many meanings of
                  > "reduce" in English, after all).[/color]

                  The English world "reduce" certainly has multiple meanings, but so
                  does "sum". I can be a noun or a verb, for instance. It can mean
                  "summary" or "gist" in addition to addition. It also can be confusing
                  by appearing to be just a synonym for "add". Now people might have
                  trouble remember what the difference between sum() and add() is.

                  In Computer Science, however, "reduce" typically only has one meaning
                  when provided as a function in a language, and programmers might as
                  well learn that sooner than later.
                  [color=blue]
                  > But, most importantly, such a design would avoid the veritable traps
                  > to which the current, too-general 'reduce' subjects the poor learner
                  > who's quite reasonably going to believe that all that generality
                  > MUST be good for something if it's been designed into a built-in.
                  > We've seen quite a few such inappropriate uses on this thread, after
                  > all.[/color]

                  That's very easy to fix:

                  FAQ
                  ---
                  Q. Should I ever pass a function with side effects into reduce() or
                  map()?

                  A. No.

                  (Unless the side-effect is just printing out debugging information,
                  or saving away statistics, or something like that.)

                  |>oug

                  Comment

                  • Andrew Dalke

                    Re: Python's simplicity philosophy

                    Douglas Alan[color=blue]
                    > Describing reduce() in 10 seconds is utterly trivial to anyone with an
                    > IQ above 100, whether or not they have ever used sum():
                    >
                    > "To add a sequence of numbers together:
                    >
                    > reduce(add, seq)
                    >
                    > To multiply a sequence of numbers together:
                    >
                    > reduce(mul, seq)[/color]
                    ...[color=blue]
                    > Any two-argument function can be used in place of add, mul, sub, or
                    > div and you'll get the appropriate result. Other interesting
                    > examples are left as an exercise for the reader."[/color]

                    This isn't enough to describe what 'reduce' does. For
                    example, after reading this someone could think that
                    reduce(add, seq) is a macros which expands to
                    seq[0] + seq[1] + seq[2] + ...
                    and that reduce(mul, seq) is the same as
                    seq[0] * seq[1] * seq[2] + ...

                    For all the examples you gave, this is correct. However,
                    reduce(pow, seq) is not the same as
                    seq[0] ** seq[1] ** seq[2] + ...
                    because the order of operations is different.
                    [color=blue][color=green][color=darkred]
                    >>> import operator
                    >>> reduce(operator .pow, [2, 3, 4])[/color][/color][/color]
                    4096[color=blue][color=green][color=darkred]
                    >>> 2**3**4[/color][/color][/color]
                    241785163922925 8349412352L[color=blue][color=green][color=darkred]
                    >>> (2**3)**4[/color][/color][/color]
                    4096[color=blue][color=green][color=darkred]
                    >>>[/color][/color][/color]

                    I would argue that a "better" way to describe 'reduce'
                    is by defining it through its implementation, as

                    def reduce(f, seq):
                    val = seq[0]
                    for x in seq[1:]:
                    val = f(val, x)
                    return val

                    or by explaining it as
                    reduce(f, (a, b)) is the same as f(a, b)
                    reduce(f, (a, b, c)) is the same as f(f(a, b), c)
                    reduce(f, (a, b, c, d)) is the same as f(f(f(a, b), c), d)
                    and reduce(f, seq) is the same as
                    f(...f(f(f(f(se q[0], seq[1]), seq[2]), seq[3]), seq[4]), ....seq[n-1])

                    As I pointed out, any approach assumes the student knows
                    what it means to pass a function around. This is not
                    something that a beginning programmer (the proverbial CS
                    101 student) necessarily knows or is taught in that course.
                    (I know that you'll disagree with that statement.)

                    As others have pointed out, you must at that time explain
                    when/why 'reduce' is useful, otherwise it is not going to be
                    remembered, or at best put away on the mental top-shelf
                    only to be pulled out on rare occasion. For that matter, are
                    you prepared to answer the question 'why is it called "reduce"?' ?

                    You've already given an example of when it's useful. You
                    said that you use it all the time, as in

                    def longer(x, y):
                    if len(y) > len(x): return y
                    else: return x

                    def longest(seq):
                    return reduce(longer, seq)

                    It took me a while but I figured out why it works and
                    why it's clever. It must have taken so long because of
                    my substandard CS education. It appears though that
                    many others in the Python world have suffered from a
                    poor CS education because there are only six uses of
                    'reduce' in the top-level of the standard library, (And
                    several are rather confusing.)

                    Of those, cvs.py has a tricky way to write
                    sum( (x[1] for x in items) )
                    and difflib.py has a way to write
                    sum( (x[-1] for x in self.get_matchi ng_blocks()) )
                    and profile.py could also be written as the simpler
                    def get_time_timer( timer=timer, sum=sum):
                    return sum(timer())
                    so 1/2 of those reduce cases are disguised 'sum's.

                    The other three are in csv.py and look something like
                    quotechar = reduce(lambda a, b, quotes = quotes:
                    (quotes[a] > quotes[b]) and a or b,
                    quotes.keys())
                    and are identical in intent to your use case -- select the
                    object from a list which maximizes some f(obj).

                    This suggests the usefulness of a new function or two,
                    perhaps in itertools, which applies a function to a list
                    of values and returns the first object which has the
                    maximum value, as in

                    def imax(seq, f = lambda x: x):
                    seq = iter(seq)
                    obj = seq.next()
                    maxobj, maxval = obj, f(obj)
                    while 1:
                    try:
                    obj = seq.next()
                    except StopIteration:
                    return maxobj
                    val = f(obj)
                    if val > maxval:
                    maxobj, maxval = obj, val

                    and an equivalent imin. Note that this is "better" than
                    your code because f(x) is only computed once per
                    object or N times total, while you compute it 2*(N-1)
                    times. In some cases the f(x) may be the most
                    expensive term in the calculation.

                    Then your 'longest' could be implemented as

                    def longest(seq):
                    return imax(seq, len)

                    and the example code from csv can be rewritten as
                    the simpler (IMO, of course):

                    quotechar = imax(quotes.key s(),
                    lambda a, quotes = quotes: quotes[a])

                    I tried looking for places in the std. lib which are better
                    expressed as a 'reduce' but that was a hard search.
                    Instead, I looked for places which compute a sum by
                    using an explicit loop, to see if they are better written in
                    some alternate form. I looked for places which used the
                    words 'sum', 'total', or 'tot', as well as places where
                    there was a '= 0' followed by a '+' within the next few
                    lines. There were very few, and the paucity suggests
                    that 'sum' isn't needed all that often. Then again, I'm
                    not one who suggested that that be a builtin function ;)

                    In fact, I only found three places.

                    Here's the two most relevant, from tarfile.py:
                    chk = 256
                    for c in buf[:148]: chk += ord(c)
                    for c in buf[156:]: chk += ord(c)

                    I wondered what it would look like using some of
                    the (all too many -- what happened to "should only be
                    one obvious way"!) variants:

                    # Using 'reduce'
                    chk = 256
                    chk = reduce(lambda x, y: x + ord(y), buf[:148], chk)
                    chk = reduce(lambda x, y: x + ord(y), buf[156:], chk)

                    # using the new 'sum' and a map
                    chk = 256
                    chk += sum(map(ord, buf[:148])
                    chk += sum(map(ord, buf[156:])

                    # using sum and list comprehensions
                    chk = 256
                    chk += sum([ord(c) for c in buf[:148])
                    chk += sum([ord(c) for c in buf[156:])

                    # using sum and the proposed generator expression
                    chk = 256
                    chk += sum( (ord(c) for c in buf[:148]) )
                    chk += sum( (ord(c) for c in buf[156:]) )

                    Personally, I think the existing code is the clearest
                    of the bunch, and the functional forms are too complicated.

                    In summary:
                    - I disagree with you that your text is the clearest way
                    to explain the 'reduce' function, since it is open to an
                    alternate interpretation and it doesn't help the people who
                    learn by understanding how things are implemented either
                    in code or in math.

                    - The use case you gave suggests that an alternate function,
                    which I named 'imax' (and 'imin'), is more useful, in part
                    because it does fewer operations

                    - In any case, for Python code the 'reduce' function is very
                    rarely used, so should not be something frequently pulled
                    from a Pythonista's toolbox and not taught in an intro. CS
                    course based on Python.

                    Andrew
                    dalke@dalkescie ntific.com


                    Comment

                    • Andrew Dalke

                      Re: Python's simplicity philosophy

                      Me:[color=blue]
                      > def imax(seq, f = lambda x: x):[/color]

                      The name, btw, is wrong. It should be 'obj_with_max_v alue'
                      'maxobj' or somesuch, since 'imax' should return the maximum
                      value of the iterator, which happens to be identical to what
                      max does.

                      The idea is the same.

                      Andrew
                      dalke@dalkescie ntific.com


                      Comment

                      • Patrick Maupin

                        Re: Python's simplicity philosophy

                        "Terry Reedy" wrote:[color=blue]
                        > "Patrick Maupin" wrote:[color=green]
                        > > (I'm curious, though, why you included "apply" in this list. I've
                        > > personally never needed it since the * enhancement to the call[/color]
                        > syntax.)
                        >
                        > I presume you mean as opposed to delete it altogether. Because apply
                        > can be used with map while * and ** cannot and at least one person has
                        > said he uses that.[/color]

                        That makes sense. It also fully supports the idea of pulling out
                        some of these features into an iterable-consumer module. Originally,
                        apply() provided functionality which would have been exceedingly
                        difficult to code in Python (I'd say "impossible ", except someone
                        would post an example using eval(), or a stupefyingly long example
                        function which works on any size list up to 10,000 elements, or
                        whatever... :), but now it's just a one-line helper function for map().

                        Regards,
                        Pat

                        Comment

                        • Andrew Dalke

                          Re: Python's simplicity philosophy

                          Douglas Alan:[color=blue]
                          > In Computer Science, however, "reduce" typically only has one meaning
                          > when provided as a function in a language, and programmers might as
                          > well learn that sooner than later.[/color]

                          There's also a __reduce__ and __reduce_ex__ in the pickle
                          protocol. See http://www.python.org/peps/pep-0307.html .
                          It's by far the most mentioned 'reduce' in the Python standard
                          library. Does it have anything to do with the 'reduce' function?
                          Not that I can tell. But I can't find an explaination for that
                          choice of a name.
                          [color=blue]
                          > FAQ
                          > ---
                          > Q. Should I ever pass a function with side effects into reduce() or
                          > map()?
                          >
                          > A. No.
                          >
                          > (Unless the side-effect is just printing out debugging information,
                          > or saving away statistics, or something like that.)[/color]

                          Or raising an exception on error. And a true functional programmer
                          would say:

                          Q: Should I ever pass a function with side effects?
                          A: No.

                          ;)
                          Andrew
                          dalke@dalkescie ntific.com


                          Comment

                          • Ville Vainio

                            Re: Python's simplicity philosophy

                            Douglas Alan <nessus@mit.edu > writes:
                            [color=blue]
                            > Well, bah! There are precious few constructs in this world that are
                            > clearer and more readable than
                            >
                            > reduce(add, seq)[/color]

                            I asked my non-programmer girlfriend what she thinks your construct
                            does - she didn't know. She immediately understood what sum(seq) does.

                            --
                            Ville Vainio http://www.students.tut.fi/~vainio24

                            Comment

                            • Ville Vainio

                              Re: Too much builtins (was Re: Python's simplicity philosophy

                              Alex Martelli <aleax@aleax.it > writes:
                              [color=blue]
                              > EEK -- and have a designed-from-scratch functional module without
                              > the warts. What about starting one as a sourceforge project, as I
                              > mentioned elsewhere?[/color]

                              At least there is

                              Download Xoltar Toolkit for free. Utility modules for Python, including functional programming support, lazy expressions and data structures, and thread pools.



                              [stuff that should remain builtins]
                              [color=blue]
                              > iter, len, pow [for the crucial 3-arguments case], range (or some
                              > preferable variant that returns an iterator), and zip seem pretty[/color]

                              +enumerate
                              [color=blue]
                              > are quite handy for interactive use, such as locals, globals,
                              > dir, vars, ..., are not all that frequently used in programs --
                              > so they might live in a module that the interactive mode gets
                              > automatically, rather than being built-ins.[/color]

                              locals and globals seem to have a natural place in builtins IMHO.
                              [color=blue]
                              > All of this would be perfect for the mailing list on Python 3.0
                              > if the latter existed. Posting it to c.l.py makes it unlikely
                              > Guido will ever consider the discussion's resuts, anyway. The[/color]

                              How about the wiki at python.org?

                              --
                              Ville Vainio http://www.students.tut.fi/~vainio24

                              Comment

                              • Ron Adam

                                Re: Too much builtins (was Re: Python's simplicity philosophy

                                On 13 Nov 2003 22:40:35 +0200, Ville Vainio
                                <ville.spammeha rdvainio@spamtu t.fi> wrote:
                                [color=blue]
                                >Douglas Alan <nessus@mit.edu > writes:
                                >
                                >[reduce]
                                >[color=green][color=darkred]
                                >> >> If someone can't understand this quickly, then they shouldn't be
                                >> >> programming![/color]
                                >>[color=darkred]
                                >> > Again, it's not "can't", it's whether they need to or not.[/color]
                                >>
                                >> If you don't want to learn a cool concept that will only take you 60
                                >> seconds to learn, then you shouldn't be programming! Or you can stick
                                >> to loops.[/color]
                                >
                                >As far as reduce goes, ppl will undoubtedly take a look at the
                                >description, understand it in well under 60 seconds, can't think of
                                >any use for the feature during the next 60 seconds (that wouldn't be
                                >clearer with explicit iteration), and forget it soon after turning the
                                >page. I didn't forget it, just wondered why such an oddball feature
                                >was a builtin. Obviously reduce can rock someone's world, but life is
                                >too short to bother if it doesn't rock yours.
                                >[color=green]
                                >> and powerful feature with a slew of specific, tailored features. If
                                >> reduce() can be relegated to a library or for the user to implement
                                >> for himself, then so can sum(). If the language is to only have one,
                                >> it should be reduce().[/color]
                                >
                                >I also think that reduce, sum, map and filter (and lots of others,
                                >__builtins__ has *too much stuff*) should be removed from builtins,
                                >but that will probably take some time (1997 years?). LC's and genexpes
                                >will take care of most of that stuff. And people can always do:
                                >
                                >from funtional import *
                                ># map, filter, reduce, curry, ... (I want lots of these :)
                                >
                                >There are also tons of functions that should be in sys, math or
                                >whatever:
                                >
                                >reload, repr, divmod, max, min, hash, id, compile, hex...
                                >
                                >What's your pet deprecation candidate? I have always thought
                                >`backticks` as repr has got to be the most useless feature around.[/color]


                                I think from a pragmatic point of view, what should be a built in
                                core, built in module, or in a standard library, should be
                                determined by how often they are needed to be used or depended on in
                                programs and modules. You could probably do a statistical annalist
                                to determine this by searching though the libraries, and a fairly
                                large library of end use applications.

                                Moving things closer to the core may increase the efficiency of the
                                most used items, and moving things further away would simplify and
                                better organize the language. It's always a trade off to some degree
                                isn't it?

                                Also, being in the core is not necessarily the fastest way. Modules
                                that accessing compiled and optimized dll's can be faster when related
                                functions are grouped so they can share code and data internally.

                                _Ron Adam

                                Comment

                                Working...