Currying or Partial Application

82 views
Skip to first unread message

Sarfaraz Nawaz

unread,
Jan 6, 2018, 9:12:20 AM1/6/18
to ISO C++ Standard - Future Proposals

As C++ is becoming more functional with its each release, I think we should also think in the direction of function partial application.

Here is one syntax (inspired from Scala):


int f(int a)(int b)(int c)  // #1
{
   
return a + b + c;
}


f
(10, 20, 30); // normal. full application

f
(10, 20)(30); // partial application

f
(10)(20, 30); // partial application

f
(10)(20)(30); // partial application



Now what if we have an overload function like:


int f(int a)(std::string b)(int c)  // #2
{
 
//...
}



then `f(10)` is ambiguous. In that case, we could disambiguate as:


auto f1 = f(10)(int); //Or  auto f1 = f(10) :: (int) ... stealing from Haskell?

f1
(20, 30); // calls #1

auto f2 = f(10)(std::string);

f2
("Might work")(20); //calls #2




Thoughts?

Jonathan Coe

unread,
Jan 6, 2018, 10:13:16 AM1/6/18
to std-pr...@isocpp.org
Do you have an example of how this would allow one to re-write code in a more maintainable way? I’m not familiar with Scala or the advantages that partial application can bring.

Thanks

Jon

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/835cc86a-2e6c-4e17-aec7-4f16cf8b085f%40isocpp.org.

Jake Arkinstall

unread,
Jan 6, 2018, 10:44:29 AM1/6/18
to std-pr...@isocpp.org

I love the functional direction of template metaprogramming and I certainly support more functional concepts in the core language. Partial application is nice, and the general idea of implanting that into C++ is something I support.

A key feature that you're avoiding here is that of flipping parameters so you can pre-fill the 1st and 3rd parameter and return a function accepting the second parameter and returning the fully evaluated expression - I think this should be a key part of your proposal. Limiting the partial application abilities because of some arbitrary parameter order would be rather frustrating/

I don't think there's any point in defining the function any differently from a normal function (i.e. parameters in different sets of parentheses). If you can utilise partial application at all, then I believe that there is no need to restrict it to functions defined in a very specific way, especially when we already have so many libraries that declare functions in the usual way.

Rather than having special syntax at all, it'd first make sense if you can explore the idea of wrapping this in some kind of existing structure. For example, a class encapsulating a function call, where each call recursively produces a sub-class expecting the next parameter until the class with only one remaining parameter, which returns the final result upon the operator() call. You'd stand a much better chance doing it that way than changing the underlying language. Fortunately there are already some minor efforts towards this, e.g. https://vittorioromeo.info/index/blog/cpp17_curry.html - also make sure you look at std::bind, as it is quite relevant here.

On Sat, Jan 6, 2018 at 3:13 PM, Jonathan Coe <jonath...@gmail.com> wrote:
Do you have an example of how this would allow one to re-write code in a more maintainable way? I’m not familiar with Scala or the advantages that partial application can bring.

Thanks

Jon

There is a lot of beauty to be found, but at the same time it introduces a different approach to thinking about problems. Here's an immediate example from the above link that is already pretty nice (although it CAN be done with lambdas, more complex examples get ugly fast):

std::vector<std::string> names{/* ... */}

auto find_in_names = 
    curried_find(std::begin(names))(std::end(names));

auto jack = find_in_names("Jack");
auto rose = find_in_names("Rose");

Jake Arkinstall

unread,
Jan 6, 2018, 11:19:05 AM1/6/18
to std-pr...@isocpp.org
On Sat, Jan 6, 2018 at 3:13 PM, Jonathan Coe <jonath...@gmail.com> wrote:
Do you have an example of how this would allow one to re-write code in a more maintainable way?

I just realised my example doesn't fit your request for maintainability. From my experience with Haskell, I can say that it often makes code highly reusable, and there are a lot of very flexible Haskell libraries that are only a few dozen lines long due to this. Once a handful of basic functions are in place, they can be used and abused in an incredible variety of ways, and you don't need to think twice about doing so. A lot of this (not all, but a lot) is due to partial application and parameter flipping.

So in terms of reusability, maintainability can be improved.

Jonathan Coe

unread,
Jan 6, 2018, 2:18:59 PM1/6/18
to std-pr...@isocpp.org
Interesting. As you say, the example you give can be done with lambdas; do you have an example where lambdas are not a good fit?

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Nicolas Lesser

unread,
Jan 6, 2018, 4:57:11 PM1/6/18
to ISO C++ Standard - Future Proposals
Do you have an example of how this would allow one to re-write code in a more maintainable way? I’m not familiar with Scala or the advantages that partial application can bring.

I imagine it is useful when you need to pass a function to an algorithm which hasn't got the exact signature the algorithm needs. Basically, what we would use std::bind or a lambda for currently:

    std::transform(Vec.begin(), Vec.end(), Vec.begin(), [](auto &&Var) { return foo(10, Var); }); // now
    std::transform(Vec.begin(), Vec.end(), Vec.begin(), foo(10)); // after

It's a bit more maintainable just because it uses less characters I guess :)
Reply all
Reply to author
Forward
0 new messages