News for hackers. Stuff that matters.
Re:Currying by kerkeslager on Sunday April 07, 2024 @04:49AM (#39959361)
You're assuming that the poster doesn't understand what currying is and you're jumping in with a correction which is kinda rude.

Instead of assuming you know better and jumping in with a correction, could you reread that post and assume that the person knows what they're talking about but isn't communicating exactly the way you would have communicated it? I.e., read with the intent of understanding intent, rather than read with the intent of correcting?

Re:Currying by ReleaseCandidat on Sunday April 07, 2024 @05:23AM (#39959551)
> but isn't communicating exactly the way you would have communicated it?

My answers are almost always less intented for the person who's post I'm responding to, but more for a general audience. As others have already posted the part about "currying isn't partial application", and I mainly wanted to add a (hopefully) understanable example.

And I would say that taking the OP's post as if he doesn't exactly know, what currying means in comparison to partia application _is_ the more favourable interpretation of their post.

Re:Currying by kerkeslager on Sunday April 07, 2024 @06:10AM (#39959733)
> My answers are almost always less intented for the person who's post I'm responding to, but more for a general audience

Same. I don't expect you're going to admit your mistake, but I'm pointing it out because the general audience is the sort of audience who is prone to this mistake (which I only know because I myself have been corrected for making this mistake).

> As others have already posted the part about "currying isn't partial application", and I mainly wanted to add a (hopefully) understanable example.

And in doing so, you're making the same mistake as those other posters, by assuming skybrian doesn't know what currying and partial application are. You're not doing your audience any favors by painting skybrian's post as if he said something wrong.

> And I would say that taking the OP's post as if he doesn't exactly know, what currying means in comparison to partia application _is_ the more favourable interpretation of their post.

How so?

Re:Currying by luc4 on Sunday April 07, 2024 @06:30AM (#39959824)
It's ironic that your responses come off as much more rude and condescending than the comment in question.
Re:Currying by skybrian on Sunday April 07, 2024 @01:35PM (#39962296)
I’m not offended. I was too brief and I can see how my post could be misleading.
Re:Currying by bheadmaster on Monday April 08, 2024 @05:29AM (#39967881)
Peak HN meta-argument.

It is easy to guess that the original comment meant that a manual re-write of a function:

    foo(a,b) {...}
to a class (example in pseudo-C++, since C++ supports operator() overloading):

    class Foo {
        Foo(a) {...}
        operator()(b) {...}
    }
is equivalent to currying the original function:

    // curried foo:
    foo(a)(b)

    // class-curried foo:
    Foo(a)(b)
But instead of explaining or mentioning this, you both went into a rant about intentions and motivations, which completely bored me, and informed me of nothing, as a member of the general audience.

Congratulations.

Re:Currying by whilenot-dev on Monday April 08, 2024 @06:46AM (#39968344)
Thank you for bringing the topic back on track!

Your example is currying in a manual fashion, so two questions remain for me:

1. How would you tell the compiler to do it for you, as a function transformation?

2. How would you curry a function with 3+ arguments?

Re:Currying by bheadmaster on Monday April 08, 2024 @10:17AM (#39969968)
I can answer both questions with a sprinkle of template magic:

    #include <iostream>
    #include <functional>

    template <typename Ret, typename First, typename ...Rest>
    class Curry {
        std::function<Ret(First, Rest...)> fn;
      public:
        Curry(std::function<Ret(First, Rest...)> fn): fn(fn) {};
        Curry<Ret, Rest...> operator()(First arg) {
            return Curry<Ret, Rest...>{[this, arg](Rest... args) {
                return this->fn(arg, args...);
            }};
        }
    };

    template <typename Ret, typename Arg>
    class Curry<Ret, Arg> {
        std::function<Ret(Arg)> fn;
      public:
        Curry(std::function<Ret(Arg)> fn): fn(fn) {};
        Ret operator()(Arg arg) {
            return this->fn(arg);
        }
    };


    int uncurried(int a, int b, int c) {
        return a + 2*b + 3*c;
    }

    int main() {
        auto curried = Curry<int, int, int, int>{uncurried};

        std::cout << curried(1)(2)(3) << std::endl;
    }
Re:Currying by whilenot-dev on Monday April 08, 2024 @10:58AM (#39970437)
I'm speechless, thank you very much! =)
Re:Currying by ghusbands on Sunday April 07, 2024 @11:42AM (#39961500)
It is clear that that poster does not understand what currying is, as defined in the first line of the article and easily found online; also, downthread [1], nor do you. Currying is when you turn a function of multiple parameters into nested functions of single parameters. Partially applying a curried function is not called currying.

Though if enough people share the confusion, I guess it becomes an alternative definition. Language evolves.

Also, in any case, a constructed object is nothing like a partially applied function, so the parallel drawn is not useful. It seems entirely reasonable in this case to assume that the poster does not have sufficient experience or knowledge.

[1] https://news.ycombinator.com/item?id=39959651

Re:Currying by skybrian on Sunday April 07, 2024 @12:44PM (#39961936)
I can see how someone might think I don’t know the difference, but it’s rather that I don’t think the details are important. They are both ways of partially applying a function. I wanted to demystify currying and show the equivalence, but I was too brief about it.

A method is a function with convenient syntax. Some of its arguments come from the “this” parameter. If the object is immutable and the method has no side-effects, it’s a pure function.

Converting a function to an immutable class with a method is a mechanical refactoring that I sometimes do, when the class has an intuitive name. The code does the same thing.

Re:Currying by kazinator on Monday April 08, 2024 @12:47AM (#39966294)
No partial application and currying are not both ways of partially applying a function. Partial application is a way of partially applying a function.

I have to concur with grandparent and also with user https://news.ycombinator.com/user?id=whilenot-dev in a sibling subthread.

Re:Currying by kazinator on Monday April 08, 2024 @01:22PM (#39971834)
We can say that when a function is curried (i.e. prepared or converted to curried form) then it supports partial application without any further transformation. In fact it happens naturally whenever the function is invoked.

E.g. if we have (lambda (x y z) (+ x y z)) converted into the curried form (lambda (x) (lambda (y) (lambda (z) (+ x y z)))), then while we do not yet have partial application, we can then partially apply just by passing arguments.

That is to say, we are partially applying in the abstract sense; if we pretend we still have a (lambda (x y z) ...) in our abstract semantics, then when we pass a value for x to the curried function, we then have effectively partially applied this abstract function, resulting in something that needs just the (y z) arguments now.

Languages that support implicit partial application erase the difference between f x y and (f x) y. That is to say, the programmer doesn't have to know whether f x y is a call two a function f with two arguments, or whether there is a partial application (f x) which binds the x argument, followed by an application of that resulting function to argument y.

Now if the language substrate is based on one-argument functions, under the hood, so that all functions with two or more arguments are implicitly transformed into one argument functions by currying, then partial application is "free", so to speak. The syntax may let you write f x y to call a function of two arguments, but the implementation is actually doing (f x) y.

Thus currying can support partial application in a similar way to how transformation of a program to CPS (continuation passing style) supports continuations. Partial application is "free" in a curried program similarly to how continuations are "free" in a CPSed program. Under CPS, you already have the return continuation as a hidden argument, so call/cc does nothing more than reveal what is hidden. Under currying, you already have a lambda that takes just one argument, and gives you a lambda that takes the next one.

Re:Currying by whilenot-dev on Monday April 08, 2024 @02:24PM (#39972426)
I think when calling a curried function it isn't easy to differentiate between a simple function application and a partial (function) application. I would make the assumption that as long as a higher-order function is called, then what we're actually doing is a function transformation and thus a partial application - when we applied all arguments except the last one, then finally, when the last argument of a first-order function (= the partially applied higher-order function) is applied, then this function can not be transformed anymore and is simply just evaluated. I'm sure there's also a difference in lazy evaluated languages and others in there, but this is beyond my competence.
Re:Currying by gedbhrdvbhd on Monday April 08, 2024 @08:52AM (#39969195)
> Also, in any case, a constructed object is nothing like a partially applied function, so the parallel drawn is not useful.

Are you being serious? The fact that closures and objects are dual is a frequently made observation. It’s not something the poster invented and it’s not (usually) controversial.

Re:Currying by ghusbands on Monday April 08, 2024 @09:25AM (#39969489)
Are you? Closures were not mentioned and are an implementation detail. In any case, an object and a bundle of closures being equivalent still has nothing to do with OP's talk of method calls being "easier to read and work[ing] better with autocomplete". Just read the original message upthread and try to make any useful meaning of it (especially in the context of turning add(1,2) into add 1 2).