views:

1440

answers:

4

What is currying?

How currying can be done in c++?

Please Explain binders in STL container?

+13  A: 

In short, currying takes a function f(x, y) and given a fixed Y, gives a new function g(x) where

g(x) == f(x, Y)

This new function may be called in situations where only one argument is supplied, and passes the call on to the original f function with the fixed Y argument.

The binders in the STL allow you do to this for C++ functions. For example:

#include <functional>
#include <iostream>
#include <vector>

using namespace std;

// declare a binary function object
class adder: public binary_function<int, int, int> {
public:
    int operator()(int x, int y) const
    {
        return x + y;
    }
};

int main()
{
    // initialise some sample data
    vector<int> a, b;
    a.push_back(1);
    a.push_back(2);
    a.push_back(3);

    // here we declare a function object f and try it out
    adder f;
    cout << "f(2, 3) = " << f(2, 3) << endl;

    // transform() expects a function with one argument, so we use
    // bind2nd to make a new function based on f, that takes one
    // argument and adds 5 to it
    transform(a.begin(), a.end(), back_inserter(b), bind2nd(f, 5));

    // output b to see what we got
    cout << "b = [" << endl;
    for (vector<int>::iterator i = b.begin(); i != b.end(); ++i) {
        cout << "  " << *i << endl;
    }
    cout << "]" << endl;

    return 0;
}
Greg Hewgill
Can you add code to explain this in c++
yesraaj
This is in c++ raj.
Marcin
Marcin: raj requested the C++ example before I added it. :)
Greg Hewgill
I wish I could vote up a comment trail. This comment chain is amusing. :)
que que
+4  A: 

Currying is a way of reducing a function that takes multiple arguments into a sequence of nested functions with one argument each:

full = (lambda a, b, c: (a + b + c))
print full (1, 2, 3) # print 6

# Curried style
curried = (lambda a: (lambda b: (lambda c: (a + b + c))))
print curried (1)(2)(3) # print 6

Currying is nice because you can define functions that are simply wrappers around other functions with pre-defined values, and then pass around the simplified functions. C++ STL binders provide an implementation of this in C++.

John Millikin
> C++ STL binders provide an implementation of this in C++.yes, but only for unary and binary functions...
ugasoft
and the broken c++03 (current c++) binders don't work with functions having reference parameters. They simply fail to cope with the reference-to-reference problem. the boost binders are way smarter
Johannes Schaub - litb
+9  A: 

Have a look at Boost.Bind which makes the process shown by Greg more versatile:

transform(a.begin(), a.end(), back_inserter(b), bind(f, _1, 5));

This binds 5 to f's second argument.

Konrad Rudolph
Konrad, since you are using the single-source form of std::transform, shouldn't you be using _1 instead of _2? The fact that you wrote bind(f, 5, _1) instead of bind(f, _1, 5) says that the variable gets plugged into f as the second argument.
ceretullis
You're right of course.
Konrad Rudolph
I cannot recommend Boost.Bind enough -- learn it, use it, love it!!
fbrereto
+6  A: 

Simplifying Gregg's example, using tr1:

#include <functional> 
using namespace std;
using namespace std::tr1;
using namespace std::tr1::placeholders;

int f(int, int);
..
int main(){
    function<int(int)> g     = bind(f, _1, 5); // g(x) == f(x, 5)
    function<int(int)> h     = bind(f, 2, _1); // h(x) == f(2, x)
    function<int(int,int)> j = bind(g, _2);    // j(x,y) == g(y)
}

Tr1 functional components allow you to write rich functional-style code in C++. As well, C++0x will allow for in-line lambda functions to do this as well:

int f(int, int);
..
int main(){
    auto g = [](int x){ return f(x,5); };      // g(x) == f(x, 5)
    auto h = [](int x){ return f(2,x); };      // h(x) == f(2, x)
    auto j = [](int x, int y){ return g(y); }; // j(x,y) == g(y)
}

And while C++ doesn't provide the rich side-effect analysis that some functional-oriented programming languages perform, const analysis and C++0x lambda syntax can help:

struct foo{
    int x;
    int operator()(int y) const {
        x = 42; // error!  const function can't modify members
    }
};
..
int main(){
    int x;
    auto f = [](int y){ x = 42; }; // error! lambdas don't capture by default.
}

Hope that helps.

Aaron