Skip to content

Instantly share code, notes, and snippets.

@phatak-dev
Last active July 2, 2021 05:03
Show Gist options
  • Save phatak-dev/766eccf8c72484ad623b to your computer and use it in GitHub Desktop.
Save phatak-dev/766eccf8c72484ad623b to your computer and use it in GitHub Desktop.
Functional Programming in C++

#Compilng You need g++ 4.9 to compile this code. Follow these steps to install g++-4.9

After installing run the following command to compile

/usr/bin/g++-4.9 -std=c++11 lambda.cpp

#Running

./a.out
#include <iostream>
#include <vector>
#include <algorithm>
/**
Example showing the function programming ideas in
C++ 11. Features used here are part of standard language.
**/
template <typename Collection,typename unop>
void for_each(Collection col, unop op){
std::for_each(col.begin(),col.end(),op);
}
template <typename Collection,typename unop>
Collection map(Collection col,unop op) {
std::transform(col.begin(),col.end(),col.begin(),op);
return col;
}
template <typename Collection,typename binop>
Collection zip(Collection fc,Collection sc,binop op) {
std::transform(fc.begin(),fc.end(),sc.begin(),fc.begin(),op);
return fc;
}
template <typename Collection,typename Condition>
bool exists(Collection col,Condition con) {
auto exist = std::find_if(col.begin(),col.end(),con);
return exist != col.end();
}
template <typename Collection,typename Predicate>
Collection filterNot(Collection col,Predicate predicate ) {
auto returnIterator = std::remove_if(col.begin(),col.end(),predicate);
col.erase(returnIterator,std::end(col));
return col;
}
template <typename Collection,typename Predicate>
Collection filter(Collection col,Predicate predicate) {
auto fnCol = filterNot(col,[predicate](typename Collection::value_type i) { return !predicate(i);});
return fnCol;
}
int main()
{
//helper println
auto println = [](const char *message){ std::cout << message << std::endl;};
auto lambda_echo = [](int i ) { std::cout << i << std::endl; };
std::vector<int> col{20,24,37,42,23,45,37};
//call foreach to print the vector
println("running foreach");
for_each(col,lambda_echo);
// add one to each element
println("running map operation");
auto addOne = [] (int i) { return i+1;};
auto returnCol = map(col,addOne);
for_each(returnCol,lambda_echo);
//zip operation
println("running zip operation");
auto zipAdd = [] (int a, int b){ return a+b;};
std::vector<int> secondCol{40,22,22,24,23,45,34};
auto zipCol = zip(col,secondCol,zipAdd);
for_each(zipCol,lambda_echo);
println("runnig exists");
//prints 1 if true 0 if false
std::cout << "value 20 exist= " << exists(col, [] (int value){ return value==20;}) << std::endl;
std::cout << "value 43 exist= " << exists(col, [] (int value){ return value==43;}) << std::endl;
println("running filterNot");
auto filterCol = filterNot(col,[](int value){ return value==23;});
for_each(filterCol,lambda_echo);
println("running filter");
auto filteredCol = filter(col,[](int value){ return value > 30;});
for_each(filteredCol,lambda_echo);
}
@stokes3452
Copy link

Looks like you can't open a pull-request on a gist, so:
In the case of no match, find_if returns last. With that in mind:

diff --git a/lambda.cpp b/lambda.cpp
index fca2ea7..3b8231e 100644
--- a/lambda.cpp
+++ b/lambda.cpp
@@ -27,7 +27,7 @@ Collection zip(Collection fc,Collection sc,binop op) {
 template <typename Collection,typename Condition>
 bool exists(Collection col,Condition con) {
    auto exist = std::find_if(col.begin(),col.end(),con);
-   return *exist != NULL;
+   return exist != col.end();
 }

@phatak-dev
Copy link
Author

@stokes3452 Thank you. updated it.

@johncorn271828
Copy link

Is there a way to generalize your map combinator so that the output collection does not necessarily have the same type as the input? For example, say I want to take a vector of ints and get a vector of vectors of ints. Perhaps I have misunderstood your code or my compiler errors?

Here is my attempt (which generates compiler errors I don't know how to fix):

template <typename Collection, typename function> 
auto map(function f, Collection c)  {
  auto result;
  std::transform(c.begin(),c.end(),result.begin(),f);
  return result;
}

@sprestel-github
Copy link

sprestel-github commented Aug 22, 2017

A more stl-ish approach of map with a the additional ability to define a different target container would be

template<typename RET_CONT, typename IT, typename OPERATION>
RET_CONT map(IT begin, IT end, OPERATION op)
{
   RET_CONT ret;
   std::transform(begin, end, back_inserter(ret), op);
   return ret;
}

its usage would then be

std::vector<int> in = { 0, 1, 2, 3 }:

typedef std::list<int> target_cont_type;
target_cont_type out = map<target_cont_type>(in.begin(), in.end(), [] (auto i) { return i * 10; });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment