Thursday, February 11, 2016

C++ <functional> concrete monad


(1)commonly used generic functor greater<>(), lesser<>(), plus<>(), multiplies<>();
(2) bind() is to be replaced by lambda
(3) lambda is Callable Object, similar to c function pointer but extended to have pmd/pmf concept=pointer to member data/reference
(4) invoke(Callable,value) is template+ functional generic code execution.
(5) from monad functional space to classical code, decay_t(result_of_t(callable(invoke)))) would do it.
(6) reference_wrapper convert value semetic in monard
(7) function is a monad recorder to playback


#include "stdafx.h"
#include <functional>
#include <vector>
#include <algorithm>
#include <iostream>
#include <random>

using namespace std;

void tryout_result_of();
void tryout_reference_wrapper();
void tryout_function();

template <typename Range,typename Callable>
void transform_print(const Range& r, Callable c)  // lambda is just a callable object from unamed type
{
 for (const auto&e :r)
 {
  cout << invoke(c, e) << endl;
 }
}

//pmd =point to member data, hard to optimize, pmf= pointer to member reference.
int main()
{
 vector<int> vint{ 11,28,3,14,5,96 };
 vector<string> vstr{ "test","jpmc","password","bankd","hou","pick peach los hand" };

 sort(vint.begin(), vint.end(), greater<>());  //functor generic type
 for (const auto&e : vint) cout << e << endl;

 cout << count_if(vint.begin(), vint.end(), bind(less<>(), placeholders::_1, 9))<<endl;   // avoid bind use lambda as below, bind has pmd

 cout << count_if(vint.begin(), vint.end(), [](const auto& p) {return p < 5; }) << endl;

 vector<pair<int, int>> vpint{ { 1,2 }, { 9,3 }, { 11, 55 } };
 transform_print(vpint, [](const auto& p) {return p.first*p.second; });  // lambda is a callable object better than bind and should replace it.
 transform_print(vpint, &pair<int, int>::second);

 tryout_result_of();
 tryout_reference_wrapper();
 tryout_function();

 getchar();
    return 0;
}


template<typename T, typename Callable>
auto transform_sort(const vector<T>& v, Callable c)
{
 vector<decay_t<result_of_t<Callable&(const T&)>>> ret;
 for (const T& t : v)
 {
  auto i = invoke(c, t);
  int ii = 0;
  ret.push_back(i);
 }
 sort(ret.begin(), ret.end());
 return ret;
}

void tryout_result_of()
{
 const vector<string> v{ "test","functional","result_of","not really functional" };
 auto lambda = [](const string& s) {return s.size(); };

 cout << endl;
 for (auto& e : transform_sort(v, lambda))
 {
  cout <<e<< endl;
 }

}

void tryout_reference_wrapper()
{
 vector<int> v(8);
 auto b = v.begin(); auto e = v.end();
 typedef uniform_int_distribution<int> Dist;
 auto d20 = [urng = mt19937(3344), dist = Dist(1, 20)]() mutable { return dist(urng); };

 generate(b, e, d20);
 for (auto a : v) cout << a << ",";
 cout << endl;
 generate(b, e, d20);   // same set of int
 generate(b, e, ref(d20));
 generate(b, e, ref(d20));  // different set due to reference_wrapper
}

int sum_square(int x, int y) { return x*x + y*y; }
void tryout_function()
{
 vector<function<int(int, int)>> v;  // record a sequence of action for later playback, only signature matter can be pmd,pmf, regular function
 v.emplace_back(plus<>());
 v.emplace_back(multiplies<>());
 v.emplace_back(&sum_square);  // can ommit &
 for (int i = 10; i <= 1000; i *= 10)
  v.emplace_back([i](int x, int y) {return i*x + y; });

 for (const auto f : v) cout << f(1, 2) << endl;
}


No comments:

Post a Comment