On Nov 14, 2013, at 7:05, Steven D'Aprano firstname.lastname@example.org wrote:
On Wed, Nov 13, 2013 at 07:13:19PM -0800, Andrew Barnert wrote:
I know this is getting way off topic, but the real problem with doing curried/auto-partial functions in Python isn't the parens, it's the variable arguments. An auto-partial function has to accumulate parameters if it doesn't get enough, execute when it does. (Currying gives you that for free, because it means you only get one argument at a time, but you can do auto-partials without currying.)
I disagree. The real problem is the ambiguity. Given:
y = divmod(x)
did I intend for y to be a partial function, or did I mean to type divmod(x, 3) but mess up? Given how few coders come from a functional programming background, my money is that it's an error.
This may be a reason not to do it, but it's not something that makes it hard or impossible to do it. Variable arguments _are_ something that makes it hard or impossible to do it.
In languages with static typing, it's easy for the compiler to resolve this: if y is declared as a function object, then I meant for the partial application. If y is declared as an int, then it's an error. But you can't do this in Python.
That's not how it works in any of the languages we're talking about. They have a type inference system, usually based on Hindley-Milner, not a C-style nominal type system.
Of course sometimes declared (or elsewhere-inferred) variable types will resolve an ambiguity during unification, but that's not the usual case; declared or inferred function types do so far more often. divmod is intint->intint (or, in a curried language, int->int->int*int), and therefore this expression is only typable if it's a partial, and y's type is inferred from the type the expression has as a partial. (And if you've declared y to have an explicit type that isn't compatible with the partial, you get a unification error.)
If you allow varargs functions, where the type can be int->int or int*int->int, HM doesn't work. And, not coincidentally, none of these languages allow varargs functions.
But to handle a vararg function, you'd need a separate syntax for partializing vs. calling.
We have that. It's called functools.partial :-)
Yes, but the (sub-)thread started off with (summarizing) "I wish we had something more brief/simple/Scala-like for partials than functools.partial". And functools.partial is not an answer to that.
Aside: am I the only one who wishes there was a functools.rpartial, that binds from the right instead of the left?
I've often wanted that. I've even built it a few times. It has the same problem with keyword arguments and keyword-only params that auto-partialing does, but it doesn't feel like as much of a limitation--you just wouldn't ever use it in those cases (especially since you can often just bind the argument by keyword in those cases).
I've also occasionally wanted a partial where you specify the indices of the arguments as keywords (which gives you rpartial just by using -1), so I could more easily bind the second of three (or even of variable) arguments. But that comes up less often.
Using a different operator like  or % or << seems attractive at first, but it can't handle keywords. You could add a method, so spam._(n=5) returns partial(spam, n=5), but ._ is hideous, and anything meaningful like bind or partial is no longer a shortcut.
And why is this a problem?
I assume you're not asking about why ._ being hideous is a problem, but why .partial being not a shortcut is a problem, right?
Offering foo.partial(n=5) as an alternative for partial(foo, n=5) doesn't provide any benefit--it's not easier to read, more obvious to write, shorter, or better in any other way. It just gives you two obvious ways to do it instead of one. Which is bad.
You read code more often than you type it, and quite frankly, creating partial applications of functions shouldn't be so common in real-world code that it needs to be so concise.
It's common in many application areas. For example, I have a row of radio buttons. Instead of defining 5 separate callback functions, I write one callback function that takes a number from 0 to 4, and then I bind each button to partial(callback, n).
Many people today instead bind each button to a lambda, I suspect because the tkinter tutorials all use lambda for this purpose instead of partial.
I've also seen people write an explicit make_btn_callback function so they can bind each button to make_btn_callback(n)
Anyway, compare these three and tell me you see zero benefit in the last one:
Button(frame, str(i), lambda event: click(i, event)) Button(frame, str(i), partial(click, i)) Button(frame, str(i), click(i, ...))