Last active
December 10, 2015 04:28
-
-
Save splinterofchaos/4381376 to your computer and use it in GitHub Desktop.
Generic Lambda fun.
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
#include <vector> | |
#include <algorithm> | |
#include <iostream> | |
constexpr struct { | |
// Ignore perfect forwarding. Assume basic types. | |
template< class X, class Y > | |
auto operator () ( X x, Y y ) | |
-> decltype(x*y) | |
{ | |
return x * y; | |
} | |
} multObj{}; | |
auto compose = | |
[]( auto f, auto g ) | |
[=]<class ...X>( X&& ...x ) | |
f( g(std::forward<X>(x)...) ); | |
template< class F > struct Forwarder : F { | |
constexpr Forwarder( const F& f ) : F(f) { } | |
}; | |
template< class R, class ...X > | |
struct Forwarder<R(*)(X...)> { | |
using type = R(*)(X...); | |
type f; | |
constexpr Forwarder( type f ) : f(f) { } | |
constexpr R operator () ( X... x ) { | |
return f( std::forward<X>(x)... ); | |
} | |
}; | |
template< class R, class ...X > | |
struct Forwarder<R(X...)> : Forwarder<R(*)(X...)> | |
{ | |
using type = R(*)(X...); | |
constexpr Forwarder( type f ) | |
: Forwarder<R(*)(X...)>(f) | |
{ | |
} | |
}; | |
template< class F, class G > | |
struct Overloaded : Forwarder<F>, Forwarder<G> { | |
constexpr Overloaded( const F& f, const G& g ) | |
: Forwarder<F>(f), Forwarder<G>(g) | |
{ | |
} | |
}; | |
template< class F > F overload( F&& f ) { | |
return std::forward<F>(f); | |
} | |
template< class F, class G, class ...H, | |
class O1 = Overloaded<F,G> > | |
auto overload( const F& f, const G& g, const H& ...h ) | |
-> decltype( overload(O1(f,g),h...) ) | |
{ | |
return overload( O1(f,g), h... ); | |
} | |
template< class X, class F > | |
struct UnaryOverload { | |
F f; | |
UnaryOverload( const F& f ) : f(f) { } | |
using result_type = typename std::result_of< F(X) >::type; | |
result_type operator () ( X x ) const { | |
return f(x); | |
} | |
}; | |
template< class ...X, class F > | |
auto unary_overload_set( const F& f ) | |
-> decltype( overload(UnaryOverload<X,F>(f)...) ) | |
{ | |
return overload( UnaryOverload<X,F>(f)... ); | |
} | |
auto cout1 = []( const auto& x ) { std::cout << x; }; | |
struct sequence_tag {}; | |
struct other_tag {}; | |
template< class S > auto get_tag(const S& s) -> decltype( std::begin(s), sequence_tag{} ); | |
template< class S > auto get_tag(...) -> other_tag; | |
template< class Tag, class F > | |
struct OverloadTag : F { | |
constexpr OverloadTag( const F& f ) : F(f) { } | |
template< class X > | |
constexpr auto operator () ( X&& x ) const | |
-> typename std::enable_if < | |
std::is_same< Tag, decltype(get_tag(x)) >::value, | |
typename std::result_of< F(X) >::type | |
>::type | |
{ | |
return F::operator()( std::forward<X>(x) ); | |
} | |
operator F() const { return *this; } | |
}; | |
template< class Tag, class F, class O = OverloadTag<Tag,F> > | |
O overload_tag( const F& f ) { | |
return O( f ); | |
} | |
void print_char( char c ) { std::cout << "'" << c << "'"; } | |
auto prnt = overload ( | |
// Anything cout is already defined for. | |
[]( const auto& x ) | |
-> decltype( void(std::cout << x) ) | |
{ std::cout << x; }, | |
// Any STL sequence. | |
[]<class Sequence>( const Sequence& s ) | |
-> decltype( void(std::begin(s)) ) | |
{ | |
std::cout << "[ "; | |
for( const auto& x : s ) | |
std::cout << x << ' '; | |
std::cout << ']'; | |
}, | |
// These are both sequences for which cout is defined. | |
// Specializing disambiguates this. | |
unary_overload_set<const char* const, | |
const std::string&>( | |
[]( auto&& s ) { std::cout << s; } | |
) | |
); | |
void prnt2_int ( int i ) { std::cout << i; } | |
void prnt2_char( char c ) { std::cout << c; } | |
auto prnt2 = overload( prnt2_int, prnt2_char ); | |
auto ycomb_impl = []( auto Y, auto f ) | |
f( [=](auto x) f(x) ); | |
auto ycomb = []( auto f ) | |
ycomb_impl( ycomb_impl, f ); | |
auto fact1 = []( auto f, auto n ) | |
not n ? 1 : f(f,n-1) * n; | |
auto fact = | |
[]( int x ) fact1( fact1, x ); | |
//auto factY = ycomb ( | |
// []( auto self ) | |
// [=]( auto n ) | |
// not n ? 1 : self(n-1) * n; | |
//); | |
auto fix = []( auto f ) | |
[=]( auto x ) f( f, x ); | |
auto fixed_fact = fix ( | |
[]( auto f, auto n ) | |
not n ? 1 : f(f,n-1) * n | |
); | |
auto fixed_fib = fix ( | |
[]( auto f, auto n ) | |
n == 0 ? 0 : | |
n <= 2 ? 1 : | |
f(f,n-1) + f(f,n-2) | |
); | |
//void f() { fact(4); } | |
//int twentyFour = fact(4); | |
//auto twentyFour = fact(4); | |
using IntToInt = int(*)(int); | |
IntToInt iToIFact = []( auto x ) not x ? 1 : x * iToIFact(x-1); | |
#include <tuple> | |
template< size_t i, class F, class T, class U > | |
auto zip_tuple_row( const F& f, T&& t, U&& u ) | |
-> decltype( f( std::get<i>(std::forward<T>(t)), | |
std::get<i>(std::forward<U>(u)) ) ) | |
{ | |
return f( std::get<i>(std::forward<T>(t)), | |
std::get<i>(std::forward<U>(u)) ); | |
} | |
template< size_t ...i, class F, class T, class U > | |
auto zip_tuple( const F& f, T&& t, U&& u ) | |
-> decltype( std::make_tuple( zip_tuple_row<i>(f,std::forward<T>(t), | |
std::forward<U>(u))... ) ) | |
{ | |
return std::make_tuple( zip_tuple_row<i>(f,std::forward<T>(t), | |
std::forward<U>(u))... ); | |
} | |
std::function<bool(unsigned int)> even; | |
auto odd = []( auto n ) n==0 ? false : even(n-1); | |
auto even1 = []( auto self, auto odd, auto n ) | |
n == 0 ? true : odd(odd,self,n-1); | |
auto odd1 = []( auto self, auto even, auto n ) -> bool | |
n == 0 ? false : even(even,self,n-1); | |
auto rec_even = []( auto n ) even1( even1, odd1, n ); | |
auto rec_odd = []( auto n ) odd1( odd1, even1, n ); | |
auto surrounder = []( auto pre, auto post ) | |
overload ( | |
[=]( std::string s ) pre + std::move(s) + post | |
//[=]( char c ) pre + std::string(1,c) + post | |
); | |
auto html_start = []( char c ) "<" + std::string(1,c) + ">"; | |
auto html_end = []( char c ) "</" + std::string(1,c) + ">"; | |
auto html_surrounder = []( char c ) surrounder( html_start(c), html_end(c) ); | |
auto html_surround = []( char c, std::string s ) -> std::string | |
html_surrounder( c )( std::move(s) ); | |
auto bold = []( std::string s ) -> std::string html_surround( 'b', std::move(s) ); | |
auto even_print = []( unsigned n ) void( std::cout << (even(n) ? "It's even!" : "Odd.") << std::endl ); | |
int main () { | |
even = []( auto n ) n==0 ? true : odd(n-1); | |
std::cout << "5 is odd : " << odd(5) << std::endl; | |
std::cout << "5 is odd : " << rec_odd(5) << std::endl; | |
std::cout << "5 is even : " << even(5) << std::endl; | |
std::cout << "5 is even : " << rec_even(5) << std::endl; | |
even_print(5); | |
std::cout << bold("Hello world") << std::endl; | |
prnt2(5); prnt2('c'); prnt2('\n'); | |
std::tuple<int,std::string> a{1,"hello "}, | |
b{2,"world!"}; | |
auto r = zip_tuple<0,1>( ([](auto x, auto y) x + y), a, b ); | |
{ | |
int a = 5, b = 5; | |
auto apply = []( auto f, auto x, auto y ) f(x,y); | |
int c = apply( ([](auto x, auto y) x + y), a, b ); | |
} | |
std::cout << "r = { " << std::get<0>(r) << ", " | |
<< std::get<1>(r) << " }\n"; | |
for( int i : {1,2,3,4} ) | |
std::cout << "fix(" << i << ") = " << fixed_fib(i) << std::endl; | |
std::cout << std::endl; | |
std::cout << "Fact 2*3*4 = " << iToIFact(4) << std::endl; | |
std::cout << "Fact 2*3*4 = " << fact(4) << std::endl; | |
std::cout << "Fact 2*3*4 = " << fixed_fact(4) << std::endl; | |
//std::cout << "Fact 2*3*4 = " << factY(4) << std::endl; | |
std::vector<int> v = {1,2,3,4}; | |
auto prod = std::accumulate ( | |
v.begin(), v.end(), 1, | |
multObj | |
); | |
std::cout << "prod = " << prod << std::endl; | |
auto add1 = []( auto x ) x + 1; | |
auto Char = []( auto c ) char(c); | |
// Prints "a + 1 = b" | |
std::cout << "a + 1 = " << compose(Char,add1)('a') << std::endl; | |
prnt(5); | |
prnt( "a string\n" ); | |
prnt(v); | |
prnt("\n"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment