Currying is all-present in functional programming. And we are not
really using it.
What is currying? It is a technique of transforming a
function that takes multiple arguments in such a way that it can be
called as a chain of functions, each with a single argument.
For example, lets look at a simpler version of fprintf function that
looks something like this:
print: (stream, message) -> do something
// Invoked like this:
print(cout, "Hello")
If we use the method often with specific streams (like cout, cerr and
a log file), we can define it in a different manner, so that we could
easily make additional versions specific to those streams. And, we don’t
need to impose our opinions of what a user wants by providing a set of
convenience functions ourselves (ok, qDebug() is something that
everybody wants, but you get the point).
print: stream -> function called print_to
print_to: message -> do something
// It would be invoked like this:
// (note that the print_to function doesn't
// really need to be named)
print(cout)("Hello")
// or
log = print(logging_stream)
err = print(cerr)
log("Hello")
err("Error world")
So, this seems totally unneeded, right? It can be quite useful when
working with generic code (for example STL algorithms). The following
example demonstrates vector partitioning for different predicates.
#include <string>
#include <iostream>
#include <algorithm>
#include <iterator>
auto less_than = [] (int i) {
return [i] (int j) {
return j < i;
};
};
template <typename B, typename M, typename E>
inline void write_partitions(B b, M m, E e)
{
std::copy(b, m, std::ostream_iterator<int>(std::cout, " "));
std::cout << " | ";
std::copy(m, e, std::ostream_iterator<int>(std::cout, " "));
}
int main(int argc, const char *argv[])
{
std::vector<int> ns { 1, -2, 3, -4, 5, -6, 7, -8, 9, -10 };
// Original vector
std::copy(ns.begin(), ns.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << " - Original vector" << std::endl;
// Partitions for numbers ranging from 0 to 9
for (int i = 0; i < 10; i++) {
auto p = std::partition(ns.begin(), ns.end(), less_than(i));
write_partitions(
ns.begin(),
p,
ns.end());
std::cout << " - Predicate: _ < " << i << std::endl;
}
return 0;
}
This is the output it generates:
-10 -2 -8 -4 -6 | 5 7 3 9 1 - Predicate: _ < 0
-10 -2 -8 -4 -6 | 5 7 3 9 1 - Predicate: _ < 1
-10 -2 -8 -4 -6 1 | 7 3 9 5 - Predicate: _ < 2
-10 -2 -8 -4 -6 1 | 7 3 9 5 - Predicate: _ < 3
-10 -2 -8 -4 -6 1 3 | 7 9 5 - Predicate: _ < 4
-10 -2 -8 -4 -6 1 3 | 7 9 5 - Predicate: _ < 5
-10 -2 -8 -4 -6 1 3 5 | 9 7 - Predicate: _ < 6
-10 -2 -8 -4 -6 1 3 5 | 9 7 - Predicate: _ < 7
-10 -2 -8 -4 -6 1 3 5 7 | 9 - Predicate: _ < 8
-10 -2 -8 -4 -6 1 3 5 7 | 9 - Predicate: _ < 9