Skip to content

Instantly share code, notes, and snippets.

@Manu343726
Last active January 23, 2024 11:41
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Manu343726/fb57746274fffc043c2a to your computer and use it in GitHub Desktop.
Save Manu343726/fb57746274fffc043c2a to your computer and use it in GitHub Desktop.
C++14 tuple continuation monad
//Author: Manu Sánchez (Manu343726). Aug 2014
//Everything started from this: http://stackoverflow.com/questions/25338795/is-there-a-name-for-this-tuple-creation-idiom
//Now, play with C++14!
#include <utility>
#include <iostream>
#include <exception>
template<typename... Ls>
struct lambdas_ : public Ls...
{
lambdas_( const Ls&... ls ) :
Ls( ls )...
{}
lambdas_(Ls&&... ls ) : Ls( ls )...
{}
};
template<typename... Ls>
lambdas_<typename std::decay<Ls>::type...> lambdas( Ls&&... ls )
{
return { std::forward<Ls>( ls )... };
}
template<typename D>
struct tuple_erase_base
{
template<typename... ARGS>
auto operator()(ARGS&&... args)
{
return static_cast<D*>(this)->tuple(std::forward<ARGS>( args )...);
}
tuple_erase_base& as_base()
{
return *this;
}
};
template<typename T>
struct tuple_erase : public tuple_erase_base<tuple_erase<T>>
{
friend class tuple_erase_base<tuple_erase<T>>;
tuple_erase( T tuple_ ) : tuple( std::move( tuple_ ) )
{}
private:
T tuple;
};
template<typename T>
tuple_erase<typename std::decay<T>::type> erase( T&& tuple )
{
return { std::forward<T>( tuple ) };
}
auto fix_rec = [](auto f)
{
return [=](auto... args)
{
return f(f,args...);
};
};
auto tuple = [](auto... args)
{
return erase([=](auto f){ return f(args...); });
};
auto as_base = [](auto... args)
{
return tuple(args...).as_base();
}
template<typename HEAD , typename... TAIL>
struct last_type
{
using type = typename last_type<TAIL...>::type;
};
template<typename T>
struct last_type<T>
{
using type = T;
};
auto ituple = [](auto... args)
{
return [=](std::size_t i)
{
return fix_rec(lambdas(
[](auto self , std::size_t j , auto head , auto... tail)
{
if( j == 0 )
return head;
else
return [=]() -> decltype(head) { return self(self , j - 1 , tail...); }();
},
[](auto self , std::size_t j) -> typename last_type<decltype(args)...>::type
{
throw std::out_of_range{"Index out of bounds"};
}
))(i,args...);
};
};
auto at = ituple;
auto identity = [](auto x)
{
return x;
};
auto map = [](auto... args)
{
return [=](auto f){ return tuple(f(args)...); };
};
auto foldl_ = [](auto self , auto... args)
{
return [=](auto f , auto state) -> decltype(state)
{
auto rec = [=](auto arg , auto... tail) -> decltype(state)
{
return self(self,tail...)(f,f(state,arg));
};
auto base = [=]()
{
return state;
};
return lambdas(rec,base)(args...);
};
};
auto foldl = [](auto... args)
{
return foldl_(foldl_,args...);
};
auto cat = []( auto... largs )
{
auto closure_ = [=](auto... rargs ) { return tuple(largs...,rargs...); };
return [=](auto rhs)
{
return rhs(closure_);
};
};
auto filter = []( auto... args )
{
return [=](auto f)
{
auto base = [](auto self , auto passed){ return passed; };
auto rec = [f](auto self , auto passed , auto head , auto... tail )
{
auto next = f(head) ? passed(cat)(tuple(head,tail...)) : passed(cat)(tuple(tail...));
return self(self, next , tail...);
};
return fix_rec(lambdas(base,rec))(tuple(),args...);
};
};
auto size = [](auto... args)
{
return sizeof...(args);
};
auto print_tuple = [](auto t , std::ostream& os = std::cout){ return t(map)( [&](auto e){ os << e << " "; return e; } ); };
int main()
{
auto t = tuple(1,2,3,4,5)(cat)(tuple(6,7,8,9))
(map)([](auto i){ return i*2; })
(map)([](auto i){ return i - 1; })
(foldl)( [](auto s , auto i){ return s + i;} , 0 );
std::cout << t << std::endl;
print_tuple( true ? tuple(1)(cat)(tuple(2))(as_base) : tuple()(cat)(tuple(1,2,3,4))(as_base);
}
@etam
Copy link

etam commented Mar 30, 2016

Cool piece of code 👍, but:

  1. some bits are missing
diff --git a/cpp14monad.cpp b/cpp14monad.cpp
index 7e6c109..20da91a 100644
--- a/cpp14monad.cpp
+++ b/cpp14monad.cpp
@@ -78,7 +78,7 @@ auto tuple = [](auto... args)
 auto as_base = [](auto... args)
 {
     return tuple(args...).as_base();
-}
+};

 template<typename HEAD , typename... TAIL>
 struct last_type
@@ -190,5 +190,5 @@ int main()

     std::cout << t << std::endl;

-    print_tuple( true ? tuple(1)(cat)(tuple(2))(as_base) : tuple()(cat)(tuple(1,2,3,4))(as_base);
+    print_tuple( true ? tuple(1)(cat)(tuple(2))(as_base) : tuple()(cat)(tuple(1,2,3,4))(as_base) );
 }
  1. does not compile:
etam@etam-komp:~/tmp/cppmonad> clang++-3.8 -std=c++14 -O3 cpp14monad.cpp -o cpp14monad
cpp14monad.cpp:193:23: error: incompatible operand types ('tuple_erase_base<tuple_erase<(lambda at cpp14monad.cpp:75:18)>>' and 'tuple_erase_base<tuple_erase<(lambda at cpp14monad.cpp:75:18)>>')
    print_tuple( true ? tuple(1)(cat)(tuple(2))(as_base) : tuple()(cat)(tuple(1,2,3,4))(as_base) );
                      ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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