

Currying in Python - Luyt
http://mtomassoli.wordpress.com/2012/03/18/currying-in-python/

======
lloeki
nitpick: camelCase burns my eyes on functions and vars in Python code, and
since that's not PEP8 compliant it makes syntastic shout at me when torturing
your examples in vim.

------
prezjordan
I love the Haskell implementation, since arguments and functions don't need
any discernible characters, f 1 2 3 4 5 works just fine. I guess this was one
of the original design features of Haskell.

~~~
Drbble
Yup. The tradeoff is that you lose multiple dispatch based on argument list
size (overloading) (Clojure, C++, and Java takes the other side of that
tradeoff. I don't know if Python has signature-overloading like that.)

~~~
rplnt
I don't think python has any sort of overloading (based on signature that is).
You can use _def f(°args, °°kwargs)_ though. What you'll get is a tuple
containing positional arguments and dictionary with keywords arguments. You
can even specify some explicitly and then consume all others with this.

edit: ° should've been * but I couldn't escape it without using spaces.

------
Drbble
Ha, I write my Javascript like this. Makes me want to just go back to Haskell
though. Does currying kill performance in Python like it does in Javascript?

To reduce clutter and unobscure the point, and support uncurried usage (like
apply(f, args) however that is done in Python) , it needs more lambdas
instead, of defs:

    
    
        f = lambda a: lambda b: f_uncurried(a, b)

~~~
kbd
> like apply(f, args) however that is done in Python

Python 2 has an apply function [1], but it was deprecated for a long time and
removed in 3.0 [2]. apply(f, args) is equivalent to f(*args) in Python.

[1] <http://docs.python.org/library/functions.html#apply>

[2]
[http://docs.python.org/release/3.0.1/whatsnew/3.0.html#built...](http://docs.python.org/release/3.0.1/whatsnew/3.0.html#builtins)

------
dustingetz
look, Python's audience isn't Haskell's audience, and all these scary words
like "curring", "incremental binding", "just like haskell", "left association"
aren't things that most Python people care about. the article makes this stuff
look like voodoo which is frustrating because functional programming doesn't
have to be voodoo.

currying is really really easy and everyday python programmers probably do it
on accident.

    
    
      def divisible(n, x): return n % x == 0
    
      def divisors(n):
          possible_divisors = range(2, int(sqrt(n))+1)
          return filter(lambda x: divisible(n, x), possible_divisors) # OMG curry !
    
      assert divisors(24) == [2, 3, 4]

~~~
tmhedberg
This argument seems silly to me. _Currying_ is the name of the technique. Why
is that scary? Should he call it something different just to avoid "scaring"
feeble programmers who are afraid of new words?

~~~
anamax
You're missing the point.

Currying isn't a big deal for python programmers. The article fails precisely
because it makes currying into a big deal.

This is yet another example of how haskell got it wrong. Currying isn't
something that one should do all the time or think about, so basing a language
on it is dumb. (And that's true even if we ignore the complications that it
adds to polymorphism.)

~~~
tmhedberg
_Currying isn't a big deal for python programmers. The article fails precisely
because it makes currying into a big deal._

I wasn't trying to imply that currying is a big deal for most Python
programmers, nor do I agree that the article was. But I think it's probably
safe to say that many Python programmers aren't familiar with it or how it can
be effectively put to use, since in Python, it's a neat, occasionally useful
technique, but isn't exactly "central" to the language. For whatever reason,
Python also tends to attract a lot of beginner programmers, who probably
haven't had enough experience to be exposed to functional techniques. I
interpreted the article as targeting that kind of audience.

 _This is yet another example of how haskell got it wrong. Currying isn't
something that one should do all the time or think about, so basing a language
on it is dumb. (And that's true even if we ignore the complications that it
adds to polymorphism.)_

Disclaimer: I like Haskell a lot, so you should probably take my opinion with
a grain of salt. I'm not trying to start an argument, just expressing a
counter-opinion.

From my point of view, Haskell's "currying by default" approach gives you what
is essentially a superset of the functionality available in most other
languages, while taking away very little. It's fine to think of `f a b c` in
Haskell as being equivalent to `f(a, b, c)` in Python, even though we know
that, under the hood, f isn't really a function of 3 arguments. It has the
same behavior as the Python version if you always fully apply it to all 3
arguments, though (ignoring strictness). But of course, Haskell conveniently
allows you to partially apply f without requiring any extra effort on your
part. At least Python gives you the functools library module to make that sort
of thing easier; most languages don't even do that.

What does automatic currying take away? Well, as you alluded, function
polymorphism based on the length of the argument list isn't as straightforward
as it is in, say, Java, since Haskell functions really only have a single
argument, period. But if you _really_ want the ability to do this kind of
overloading, it can be accomplished using type classes. And Python's
optional/keyword arguments can be emulated using record syntax. It's just not
particularly common to use these techniques, because most of the time there
are much more idiomatic ways of accomplishing the things you might use
function overloading for in a different language.

I'd be interested to hear what else you think is lost as a result of automatic
currying. It's difficult for me to come up with anything other than benefits,
but maybe I am being blinded by my enthusiasm for the language.

~~~
anamax
> I'd be interested to hear what else you think is lost as a result of
> automatic currying.

How about I use one of your examples.

> It's fine to think of `f a b c` in Haskell as being equivalent to `f(a, b,
> c)` in Python, even though we know that, under the hood, f isn't really a
> function of 3 arguments.

All abstractions leak. The fact that Haskell is always curried means that you
always have to be aware of currying.

There are many kinds of problem solving. One is "how do I solve {x} using {y}
in some clever way." Haskell is great for those folk. Another is "How do I
solve {x}."

Here's one way to distinguish these two groups. The first sends "look at my
cute solution to {x}" to their friends while the latter say they send "look at
what I built".

To put it another way, when a user community is dominated by folks who write
papers/essays about the tools, you've got a tool for folks who want to play
with tools.

Haskell is wonderful for a subset of those folks who care a lot about tools,
specifically those folks who think that mathematical purity is important.

There are other goals.

~~~
tmhedberg
_The fact that Haskell is always curried means that you always have to be
aware of currying._

No, you don't. That was my point.

By pretending that functions aren't curried, you're limiting yourself to a
subset of the language's full expressiveness, but it is a completely
consistent subset; it behaves precisely as you would expect it to in the
absence of currying. And that subset is equivalent to the expressiveness of
Python (or any other language) without currying.

It sounds like you're implying that Haskell is just an odd assortment of
academic "cute tricks" for impressing people who have nothing more important
to spend their time on, and that any practical programmer would steer clear of
it in order to "get things done". Frankly, this is the opinion of someone who
has little experience with the language, or with functional programming in
general. There are many ideas in Haskell which are unusual, or of seemingly
little value to someone with a strictly imperative background. But as anyone
who has used the language to build something practical can tell you, these
"tricks" are much more than clever mathematical toys; they enable you to
express your intent more succintly and with greater precision than with the
tools provided by most other languages, with strong compile-time guarantees of
correctness to boot. You tend to miss them quite a bit when using languages
which lack these features.

Not everyone who uses Haskell falls in love with it, and there are plenty of
arguments to be made both for and against the language, but your dismissive
characterization is just naive.

~~~
anamax
> It sounds like you're implying that Haskell is just an odd assortment of
> academic "cute tricks" for impressing people who have nothing more important
> to spend their time on,

Not at all. It's a very elegant system which attracts folks who really want to
think about tools. That's not surprising, since that's what Simon Peyton-Jones
(haskell creator) designed it for.

~~~
tmhedberg
OK, fair enough. Though I'm not quite sure what you mean by "thinking about
tools". If you're referring to the language as a tool, I personally haven't
found that I spend more time thinking about the language when using Haskell
than I do when using C, Python, Java, etc. In fact, many of the abstractions
it provides make it easier to just "say what I mean" and not worry so much
about the gritty details of the language. If I get something wrong in terms of
syntax or types, the compiler will catch it for me. At the opposite end of the
spectrum, in C, problematic code often just means "Segmentation fault" gets
printed to stderr and I'm left without meaningful feedback about where I
screwed up.

Anyway, I apologize for misinterpreting your tone.

------
kbd
I'm glad he made the correct distinction between partial application and
currying. The article is worth it for his helpful explanation of the two
alone.

Though, it's slightly off on the initial presentation of currying. Currying is
the act of _transforming_ a function that takes multiple arguments into a
function that returns a function that takes n-1 arguments, and so on, not an
"incremental binding of function arguments".

~~~
Drbble
I don't see a meaningful difference in the cases in your last paragraph. Seems
like an implementation detail.

The issue of whether the caller has to explicitly call "partial" seems to be
the meaningful distinction.

~~~
wildanimal
The original statement could be interpreted in this way: the former operation
'returns a function' and in the latter, it 'bind[s] [...] arguments' -
suggesting a form of destructive updating of the original function. But I
agree with you that in this context, since both return functions it's an
implementation detail.

------
sudhirj
There's also a complementary article I wrote last year on
<http://hangar.runway7.net/partial-functions-in-python>

