reduce() anomaly?

  • Thread starter Stephen C. Waterbury
  • Start date
T

Terry Reedy

Alex Martelli said:
Terry Reedy wrote:

Hmmm, nobody else seemed to have any problem understanding my quip,

Among those who dared respond ...
including the poster at which it was directed. Let me spell it out
for you:

Since, as I said, your target was obscure to me, thank you...
a few people are attacking 'sum' and defending 'reduce'
because the latter is "more general".

Oh.... so that was your target.

Since reduce with initializer is completely general, equivalent to an
initialized for loop (which is why I might instead call it 'induce' or
'repeat'), and hence as or more general than max, min, range,
enumerate, map, filter, list.count, and man other functions and
methods, and since none of these other 'less general than reduce'
functions have been similarly attacked that I have noticed, the
special-case, ad-hominen-like attacks on 'sum' had mostly passed
beneath my notice as devoid of memorable content.

A consistent preference for either or both of 'more general' and 'only
one way to do it' might lead us toward a very lean Python with exactly
one general repetition-with-variation function -- either 'for'
statements or something equivalent to reduce with required
initializer. But I have not noticed anyone proposing that.
So, no, I don't think my idea of "more general" is different from
yours: e.g., a function that, given a sequence, returns its length
AND the number of times 'None' occurs as an item, is more general
than one which just returns the length. That does not make it in
any intrinsic way "necessarily preferable" -- and THAT is my point.

Agreed. Generic versus specific involves tradeoff and balance.

In my garage-workshop tool set, I have perhaps 10 different general
(adjustable) wrenches, pliers, and grips, 5 specialize (fixed-size)
box-end wenches, and perhaps 30 sockets (both metric and 'English').
I have used most of them except for the large sockets meant for auto
and truck work I don't do. So I am glad to have all of them.

Terry J. Reedy
 
T

Terry Reedy

Alex Martelli said:
Just replacing the keyword 'lambda' with 'func'? If you were
designing a green-field language, and couldn't find any other way
to express callable literals -- so it only came down to a 2-way
choice between lambda and func as keywords with the same semantics,
I guess I would suggest func as the lesser evil.

If such a change were plausibly within the boundaries changes allowed
for the as-yet hypothetical 3.0 (or 3000), and there were not a more
radical change that I preferred, I might seriously propose this.
Upgrading would be simple than most other code-break changes.
How would this notation imply that x is an argument rather than,
say, a global?

The above was a minimal 'concept' proposal to test the aesthetics of
something structurally different from current 'lambda's. I think I
would make all identifiers params by default, since I believe this to
be more common, and 'tag' non-locals, perhaps with one of the
reserved, as yet unused symbols. Example: lambda x: x + y == `x + @y`
or `x+y@`. Since expressions cannot assign, no global declaration is
needed.

Terry
 
D

Donn Cave

Quoth Ville Vainio <[email protected]>:
....
| I was merely arguing that 'reduce' is not more readable or intuitive
| than 'sum', which was the argument of OP.

My point is that readability and intuition depend on acquired
experience. Your non-programmer girlfriend lacks enough experience
to be able to understand all kinds of stuff in Python, so she's not
a useful gauge, because at that level you can't use Python anyway.
It isn't that simple, and I don't think there really is any good
evidence for what is readable. We could talk about why someone might
think reduce is about readability, but it can only be speculation.

| I wouldn't mind Python getting more influence from functional realm,
| as Python seems to me to be *the* hybrid language that can pull the FP
| thing while still remaining practical and intuitive (and delightfully
| non-academic).

Python may be a hybrid, but certainly none of its parents were FPLs.
Trying to make it one gives both Python and FP a bad name. If you
want a language that really supports both functional and procedural
styles, I think you need Lisp. Look at Dylan, I haven't tried it but
it may be quite a bit more comfortable for Python and C programmers.

Donn Cave, (e-mail address removed)
 
G

Georgy Pruss

Maybe, it's worth to have str(x,8) and str(x,16) instead of oct(x) and hex(x)
and make str() a true inverse function to int()?
G-:
 
G

Georgy Pruss

| <..>
| Because as much as it helps when reading the code to only have to learn a
| minimal set of controls the same applies to writing code as well. When I
| approach a problem I don't have to agonize over "well, should I do a
| do...until(), a for(;;), a while(), or something else?" It breaks down to
| this.

I can't agree here. I NEVER wondered which of constructions should I
use in any particular case. I just solved the problem and wrote its solution
in that language and the language HELPED me to express myself clearly.

| Is it a sequence? For. Is it a condition to be met? While. There,
| done, move along.

Aha. Half of all the conditions in real Python programs are 1 or True. :)

| --
| Steve C. Lamb | I'm your priest, I'm your shrink, I'm your
| PGP Key: 8B6E99C5 | main connection to the switchboard of souls.
| -------------------------------+---------------------------------------------
 
A

Andrew Dalke

Paul Rubin:
The change was that native lists will implement stable sort. My gripe
is that if native lists are required to sort stably and list-alikes
can sort unstably, then list.sort and listalike.sort act differently
in a way that can lead to subtle bugs. ...

It would be icky if some .sort() methods are required to be stable but
others are not.

I've been thinking about this. I'm of two minds about it, both
for and against.

The 'for' side, which dominates, says that the only extra work is
for those people who implement a version of Python. There will
only be few of these, and the work needed to implement at least
a rough cut at a stable sort is pretty minimal. Any user of a list-alike
sort who is concerned about its stability or wants the code to work
for pre-2.3 will use the DSU idiom. People who don't know about
differences in how sort algorithms handle ties will have their sorts
work "as expected".

The 'against' side says, as you do, that having list.sort required
to be stable now places an extra barrier to anyone else who
implements a list-alike sort, because that sort should now also
be stable.

What mollifies the latter view is that some user-defined sorts
won't have ties, so there will never be a problem. And some
user-defined sorts will want a stable sort -- anything which
sorts rows based on a column in a grid display must be stable.
So there are only going to be a relatively few cases where
this will be a problem.

Besides, what I really want is a set of algorithms implemented
independent of the container so that I can have a generic
'sort' function work on a user-defined container. At that
point it would be trivial for a user-defined list-alike to
implement its .sort() method as a call to the stable-sort
algorithm, which further reduces the number of times when
the expectation of a stable sort causes a problem.

Hmmm.. To do this nicely would seem to require a
'swap' method on lists as otherwise there's a lot of
movements when swapping two items in a list.
Note that the most obvious way to implement sort() in C is to call the
standard C library qsort function, which is unstable.

And again I note that I've seen commercial software which
made the expectation that C's qsort(3C) was ... well, not
stable, but it assumed it would give the same results on
different machines. That error was fixed by implementing
their own sort algorithm. (It wasn't caught for years because
there are very few ties in their data and even fewer people
moved data from one platform to another.)

My preference is for a stable sort. It works the right way
for most cases, and no sort algorithm is going to do the
right thing for all cases. (Hence the explosion of sort
variants you rightly pointed out.)

Andrew
(e-mail address removed)
 
A

Andrew Dalke

Terry Reedy:
Perhaps my career in statistics and data reduction made reduce() more
immediately obvious to me than some other people.

I know when I first saw reduce, in Python BTW, I did not
intuit that meaning. I was in physics grad school and
with a bachelor's in math, with an emphasis in analysis, so
my math background was pretty strong. (Though nowadays
I look through my books and wonder that I actual knew
all that once upon a time... *sigh*)

Andrew
(e-mail address removed)
 
V

Ville Vainio

Donn Cave said:
Python may be a hybrid, but certainly none of its parents were FPLs.
Trying to make it one gives both Python and FP a bad name. If you

I don't think there is much "trying to make Python a FPL" involved w/
making lots of tried-and-true FPL constructs available in Python. It's
just taking stuff that works and enabling us to use it w/o encumbering
the language (because it's in the modules). It's all good as long as
we don't go the way of doing everything w/ recutrsion.
want a language that really supports both functional and procedural
styles, I think you need Lisp. Look at Dylan, I haven't tried it but
it may be quite a bit more comfortable for Python and C programmers.

Lisp is too verbose for my tastes (I don't want to write 'let' ot
'setq'), doesn't have much in the way of libs and generally doesn't
feel as 'right' as Python (I do use Emacs Lisp occasionally,
though.. and will try out some CL one of these days). Dylan, OTOH,
doesn't seem to be all that active a project, at least the last time I
checked.
 
A

Andrew Dalke

Georgy Pruss:
Maybe, it's worth to have str(x,8) and str(x,16) instead of oct(x) and hex(x)
and make str() a true inverse function to int()?

What then are the results of
str(30+44j, 16)
str(3.1415926, 8)
str([9, 8, 7], 8)
str("A", 16)
str({"A": 20}, 16)
?

Andrew
(e-mail address removed)
 
G

Georgy Pruss

|
| | <...>
|
| > > How about a very hypothetical (post ``==repr deprecation)
| > > results = sequence..map(`x+23`)
| >
| > How would this notation imply that x is an argument rather than,
| > say, a global?
|
| The above was a minimal 'concept' proposal to test the aesthetics of
| something structurally different from current 'lambda's. I think I
| would make all identifiers params by default, since I believe this to
| be more common, and 'tag' non-locals, perhaps with one of the
| reserved, as yet unused symbols. Example: lambda x: x + y == `x + @y`
| or `x+y@`. Since expressions cannot assign, no global declaration is
| needed.
|
| Terry

Or maybe
lambda x: x + y == `x: x + y`

G-:
 
A

Andrew Dalke

Georgy Pruss:
I NEVER wondered which of constructions should I
use in any particular case. I just solved the problem and wrote its solution
in that language and the language HELPED me to express myself clearly.

While I, when writing Perl code, also NEVER had a problem. I
ignored just about all of its variations
if ($cond) {$a++}
$a++ if $cond;
$a++ unless !($cond);
unless (!($cond)) {$a++};

I almost only used the first of these, and when other variations
in structure came up I again had a strong preference for the one
closest to C in feel. I did this not because it was the most expressive
but because I wanted to write code that others could follow,
and indeed one of the praises I got was "wow! It's Perl code I
can actually understand!"
Half of all the conditions in real Python programs are 1 or True. :)

Cute as a joke, but in real-life it omits while loops, wherein
the conditionals usually end up being true. ;)

x = 1
while x < 1000:
print x
x = x + random.random(10)

Andrew
(e-mail address removed)
 
V

Ville Vainio

Andrew Dalke said:
Georgy Pruss:
Maybe, it's worth to have str(x,8) and str(x,16) instead of oct(x) and hex(x)
and make str() a true inverse function to int()?

What then are the results of
str(30+44j, 16)
str(3.1415926, 8)
str([9, 8, 7], 8)
str("A", 16)
str({"A": 20}, 16)
?

TypeError?
 
G

Georgy Pruss

| Georgy Pruss:
| > Maybe, it's worth to have str(x,8) and str(x,16) instead of oct(x) and
| hex(x)
| > and make str() a true inverse function to int()?
|
| What then are the results of
| str(30+44j, 16)
| str(3.1415926, 8)
| str([9, 8, 7], 8)
| str("A", 16)
| str({"A": 20}, 16)
| ?
|
| Andrew
| (e-mail address removed)

I guess, the same as for
hex(30+44j)
oct(3.1415926)
oct([9, 8, 7])
hex("A")
hex({"A": 20})

G-:
 
S

Steve Lamb

While I, when writing Perl code, also NEVER had a problem. I
ignored just about all of its variations
if ($cond) {$a++}
$a++ if $cond;
$a++ unless !($cond);
unless (!($cond)) {$a++};

Exactly the case I was thinking of when I wrote my message. 4 ways to
express an if. After getting over the neatness factor I wrote if in exactly
one way. if ($cond) { block }. I found that by doing so my code was not only
far more readable to other people in general it was readable by *ME* just a
few weeks later.

I think the same thing every time we get someone asking for do...until or
do...while. We have while. If I want exactly 1 run before the condition is
tested I can do that. It seems far clearer to me when I see...

x = 1
while x < 2:
x = foo()
print "done"

...what is going on than having to deal with someone putting:

do:
x = foo()
while x < 2:
print "done"

...or having to deal with people who will read my code and tell me "Ya
know, you should use a do...while here." "Why? It's just another form of
while." "Well, yeah, but it guarentees the loop performs once." "So?
Initilizing your variables does that, too."
I did this not because it was the most expressive but because I wanted to
write code that others could follow, and indeed one of the praises I got was
"wow! It's Perl code I can actually understand!"

Same here. The latest compliment was that upon seeing an example of
Python and PHP code that did the same thing that my code was "concise and
clear". It is because I code with consistent structure, not with expressive
structure.
 
A

Andrew Dalke

Georgy Pruss:
I guess, the same as for
hex(30+44j)
oct(3.1415926)
...

Which means you want
str(obj) -> result as usual; takes any object, returns a string, all
numbers
are represented in base 10
str(obj, [base=10]) -> converts integer objects (only!) to the given base,
defaults to base 10.

That feels wrong to me. Base conversion is enough of a special
case that it doesn't warrant being part of the standard str constructor.
As an 'int.to_base' method or class method, perhaps, but not in str.

Andrew
(e-mail address removed)
 
D

Donn Cave

Ville Vainio said:
Lisp is too verbose for my tastes (I don't want to write 'let' ot
'setq'), doesn't have much in the way of libs and generally doesn't
feel as 'right' as Python (I do use Emacs Lisp occasionally,
though.. and will try out some CL one of these days). Dylan, OTOH,
doesn't seem to be all that active a project, at least the last time I
checked.

The current version of Gwydion Dylan http://www.gwydiondylan.org/
is a whole 2 months old, with a fairly good selection of supported
platforms.

Donn Cave, (e-mail address removed)
 
G

Gerrit Holl

Andrew said:
str(obj, [base=10]) -> converts integer objects (only!) to the given base,
defaults to base 10.

Well, str could be defined as follows:

def str(obj, **kwargs):
return obj.__str__(**kwargs)

That doesn't feel too wrong to me.

yours,
Gerrit.
 
G

Georgy Pruss

| Georgy Pruss:
| > I guess, the same as for
| > hex(30+44j)
| > oct(3.1415926)
| ...
|
| Which means you want
| str(obj) -> result as usual; takes any object, returns a string, all
| numbers
| are represented in base 10
| str(obj, [base=10]) -> converts integer objects (only!) to the given base,
| defaults to base 10.
|
| That feels wrong to me. Base conversion is enough of a special
| case that it doesn't warrant being part of the standard str constructor.
| As an 'int.to_base' method or class method, perhaps, but not in str.
|
| Andrew
| (e-mail address removed)

To me, it's very wrong that you can read any radix numbers, but can't
print them. If str(int(s)) == s and int(str(n)) == n (with some limits), I don't
see why str(n,radix) can't be symmetrical to int(s,radix).

BTW there's no symmetry for str() and list()/tuple()/dict() etc.
 
A

Andrew Dalke

Georgy Pruss:
To me, it's very wrong that you can read any radix numbers, but can't
print them. If str(int(s)) == s and int(str(n)) == n (with some limits), I don't
see why str(n,radix) can't be symmetrical to int(s,radix).

But your objection would also be handled with a special-case function
which only took an int/long and a base and returned the string
representation for that base, no? This could be a method or a class
method of int, or a new function in math. What makes it special enough
to warrant being part of the string constructor?
BTW there's no symmetry for str() and list()/tuple()/dict() etc.

There is a symmetry for str(float(s)) == s and str(complex(s)) == s.
Why shouldn't those take a base?

Well, almost symmetry. str(float("1.1")) != "1.1"

Andrew
(e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,172
Messages
2,570,934
Members
47,475
Latest member
ShannonGro

Latest Threads

Top