It's common knowledge that Functional Programming is spreading like a wildfire in mainstream languages. Latest promoted languages: Java 8 and C++, both of which now support lambdas. So, let the lambdas begin! and may the fun be ever on your side. The same text is available in slides form on Slideshare. This blog post and the talk/slides are inspired by JSON inventor Douglas Crockford.
Write an Identity function that takes an argument and returns the same argument.
Write an Identity function that takes an argument and returns the same argument.
auto Identity = [](auto x) {Write 3 functions add, sub, and mul that take 2 parameters each and return their sum, difference, and product respectively.
return x;
};
Identity(3); // 3
auto add = [](auto x, auto y) {Write a function, identityf, that takes an argument and returns an inner class object that returns that argument.
return x + y;
};
auto sub = [](auto x, auto y) {
return x - y;
};
int mul (int x, int y) {
return x * y;
};
auto identityf = [](auto x) {Write a function, identityf, that takes an argument and returns a function that returns that argument.
class Inner {
int x;
public: Inner(int i): x(i) {}
int operator() () { return x; }
};
return Inner(x);
};
identityf(5)(); // 5
auto identityf = [](auto x) {Lambda != Closure
return [=]() { return x; };
};
identityf(5)(); // 5
- A lambda is just a syntax sugar to define anonymous functions and function objects.
- A closure in C++ is a function object which closes over the environment in which it was created. The line #2 above defines a closure that closes over x.
- A lambda is a syntactic construct (expression), and a closure is a run-time object, an instance of a closure type.
- C++ closures do not extend the lifetime of their context. (If you need this use shared_ptr)
auto fromto = [](auto start, auto finish) {Write a function that adds from two invocations.
return [=]() mutable {
if(start < finish)
return start++;
else
throw std::runtime_error(“Complete");
};
};
auto range = fromto(0, 10);
range(); // 0
range(); // 1
auto addf = [](auto x) {Write a function swap that swaps the arguments of a binary function.
return [=](auto y) {
return x+y;
};
};
addf(5)(4); // 9
auto swap =[](auto binary) {Write a function twice that takes a binary function and returns a unary function that passes its argument to the binary function twice.
return [=](auto x, auto y) {
return binary(y, x);
};
};
swap(sub)(3, 2); // -1
auto twice =[](auto binary) {Write a function that takes a binary function and makes it callable with two invocations.
return [=](auto x) {
return binary(x, x);
};
};
twice(add)(11); // 22
auto applyf = [](auto binary) {Write a function that takes a function and an argument and returns a function that takes the second argument and applies the function.
return [=](auto x) {
return [=](auto y) {
return binary(x, y);
};
};
};
applyf(mul)(3)(4); // 12
auto curry = [](auto binary, auto x) {Currying (schönfinkeling)
return [=](auto y) {
return binary(x, y);
};
};
curry(mul, 3)(4); // 12
- Currying is the 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.
- In lambda calculus functions take a single argument only.
- Must know Currying to understand Haskell.
- Currying != Partial function application
auto addFour = [](auto a, auto b,Without creating a new function show 3 ways to create the inc function.
auto c, auto d) {
return a+b+c+d;
};
auto partial = [](auto func, auto a, auto b) {
return [=](auto c, auto d) {
return func(a, b, c, d);
};
};
partial(addFour,1,2)(3,4); //10
auto inc = curry(add, 1);Write a function composeu that takes two unary functions and returns a unary function that calls them both.
auto inc = addf(1);
auto inc = applyf(add)(1);
auto composeu =[](auto f1, auto f2) {Write a function that returns a function that allows a binary function to be called exactly once.
return [=](auto x) {
return f2(f1(x));
};
};
composeu(inc1, curry(mul, 5))(3) // 20
auto once = [](auto binary) {Write a function that takes a binary function and returns a function that takes two arguments and a callback.
bool done = false;
return [=](auto x, auto y) mutable {
if(!done) {
done = true;
return binary(x, y);
}
else
throw std::runtime_error("once!");
};
};
once(add)(3,4); // 7
auto binaryc = [](auto binary) {Write 3 functions:
return [=](auto x, auto y, auto callbk) {
return callbk(binary(x,y));
};
};
binaryc(mul)(5, 6, inc) // 31
binaryc(mul)(5,6,[](int a) { return a+1; });
- unit – same as Identityf
- stringify – that stringifies its argument and applies unit to it
- bind – that takes a result of unit and returns a function that takes a callback and returns the result of callback applied to the result of unit.
auto unit = [](auto x) {Then verify.
return [=]() { return x; };
};
auto stringify = [](auto x) {
std::stringstream ss;
ss << x;
return unit(ss.str());
};
auto bind = [](auto u) {
return [=](auto callback) {
return callback(u());
};
};
std::cout << "Left Identity "Why are unit and bind special? Read more about them here.
<< stringify(15)()
<< "=="
<< bind(unit(15))(stringify)()
<< std::endl;
std::cout << "Right Identity "
<< stringify(5)()
<< "=="
<< bind(stringify(5))(unit)()
<< std::endl;
0 comments:
Post a Comment