3 ms·
No, not exactly. And partial application of any function is nowadays possible using anonymous functions to wrap the original one, no need for constructors and s
by ReleaseCandidat 3y ago
No, not exactly. And partial application of any function is nowadays possible using anonymous functions to wrap the original one, no need for constructors and special methods.
What currying in Haskell and any other ML does, is the following as Javascript. Let's say we have a function with four parameters `func(a, b, c, d) {return a + b + c + d;}`, then the curried version is the following:
func = (a) => {
return (b) => {
return (c) => {
return (d) => a + b + c + d;
}
}
}
- kerkeslager 3y agoYou'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?
- ReleaseCandidat 3y ago> 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.
- kerkeslager 3y ago> 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?
- luc4 3y agoIt's ironic that your responses come off as much more rude and condescending than the comment in question.
- deleted 3y ago[deleted]
- skybrian 3y agoI’m not offended. I was too brief and I can see how my post could be misleading.
- bheadmaster 3y agoPeak 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.
- whilenot-dev 3y agoThank 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?
- bheadmaster 3y agoI 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; }
- ghusbands 3y agoIt 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 https://news.ycombinator.com/item?id=39959651
- skybrian 3y agoI 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.
- kazinator 3y agoNo 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 https://news.ycombinator.com/user?id=whilenot-dev in a sibling subthread.
- kazinator 3y agoWe 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.