Last active
January 23, 2024 11:41
-
-
Save Manu343726/fb57746274fffc043c2a to your computer and use it in GitHub Desktop.
C++14 tuple continuation monad
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Cool piece of code 👍, but: