神刀安全网

Fun with Lambdas: C++14 Style

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 .

auto Identity = [](auto x) {   return x; }; Identity(3); // 3

Write 3 functions add, sub, and mul that take 2 parameters each and return their sum, difference, and product respectively.

auto add = [](auto x, auto y) {   return x + y; };  auto sub = [](auto x, auto y) {   return x - y; }; int mul (int x, int y) {   return x * y; };

Write a function, identityf, that takes an argument and returns an inner class object that returns that argument .

auto identityf = [](auto x) {   class Inner {     int x;     public: Inner(int i): x(i) {}     int operator() () { return x; }   };   return Inner(x); }; identityf(5)(); // 5

Write a function, identityf, that takes an argument and returns a function that returns that argument .

auto identityf = [](auto x) {   return [=]() { return x; }; }; identityf(5)(); // 5

Lambda != Closure

  • 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)

Write a function that produces a function that returns values in a range .

auto fromto = [](auto start, auto finish) {       return [=]() mutable {           if(start < finish)               return start++;           else               throw std::runtime_error(“Complete");       };   }; auto range = fromto(0, 10);  range(); // 0 range(); // 1

Write a function that adds from two invocations .

auto addf = [](auto x) {   return [=](auto y) {      return x+y;    }; }; addf(5)(4); // 9

Write a function swap that swaps the arguments of a binary function .

auto swap =[](auto binary) {   return [=](auto x, auto y) {     return binary(y, x);   }; }; swap(sub)(3, 2); // -1

Write a function twice that takes a binary function and returns a unary function that passes its argument to the binary function twice .

auto twice =[](auto binary) {   return [=](auto x) {     return binary(x, x);   }; }; twice(add)(11); // 22

Write a function that takes a binary function and makes it callable with two invocations .

auto applyf = [](auto binary) {   return [=](auto x) {      return [=](auto y) {       return binary(x, y);      };   }; }; applyf(mul)(3)(4); // 12

Write a function that takes a function and an argument and returns a function that takes the second argument and applies the function .

auto curry = [](auto binary, auto x) {   return [=](auto y) {      return binary(x, y);   }; }; curry(mul, 3)(4); // 12

Currying (schönfinkeling)

  • 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

Partial Function Application

auto addFour = [](auto a, auto b,                    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

Without creating a new function show 3 ways to create the inc function .

auto inc = curry(add, 1); auto inc = addf(1); auto inc = applyf(add)(1);

Write a function composeu that takes two unary functions and returns a unary function that calls them both .

auto composeu =[](auto f1, auto f2) {   return [=](auto x) {     return f2(f1(x));   }; }; composeu(inc1, curry(mul, 5))(3) // 20

Write a function that returns a function that allows a binary function to be called exactly once .

auto once = [](auto binary) {       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

Write a function that takes a binary function and returns a function that takes two arguments and a callback .

auto binaryc = [](auto binary) {       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; });

Write 3 functions:

  • 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) {    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());       };   };

Then verify.

std::cout << "Left Identity "             << stringify(15)()            << "=="            << bind(unit(15))(stringify)()           << std::endl;  std::cout << "Right Identity "            << stringify(5)()            << "=="           << bind(stringify(5))(unit)()           << std::endl;

Why are unit and bind special? Read more about them here .

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Fun with Lambdas: C++14 Style

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮