Created
October 24, 2014 15:34
-
-
Save scientific-coder/5215b738a2462a0b8ad8 to your computer and use it in GitHub Desktop.
FizzBuzz in C++ with some influence ☺
This file contains hidden or 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 <iostream> | |
#include <iterator> | |
#include <string> | |
#include <tuple> | |
#include <functional> | |
#include "transducers.hxx" | |
#include "tuple_reader.hxx" | |
// usage: seq 1 20 |./FizzBuzz 3 Fizz 5 Buzz | |
int main(int argc, char* argv[]){ | |
typedef int data_t; | |
typedef std::tuple<data_t, std::string> tuple_t; | |
typedef std::function<tuple_t(tuple_t)> fun_t; // for type erasure & copy cstor of lambda | |
typedef decltype(std::cout)& out_t; | |
std::istream_iterator<data_t> b(std::cin), e; | |
transduce(comp(map([](data_t value){return tuple_t(value, std::string());}) | |
, map(transduce(comp(tuple_reader<tuple_t>() | |
, map([](tuple_t factor_name){return [factor_name](tuple_t value_name){ | |
return (std::get<0>(value_name) % std::get<0>(factor_name)) | |
? value_name | |
: tuple_t(std::get<0>(value_name) | |
, std::get<1>(factor_name) + std::get<1>(value_name));};})) | |
, compose_functions<fun_t>{} | |
, fun_t([](tuple_t t){return t;}) | |
, argv+1, argv+argc)) | |
, map([](tuple_t const& value_name) | |
{ return std::get<1>(value_name).empty() | |
? std::to_string(std::get<0>(value_name)) : std::get<1>(value_name);})) | |
, [](out_t out, std::string const& s)->out_t {return out << s << ' ';} | |
, std::ref(std::cout), b, e).get() << std::endl; | |
return 0; | |
} |
This file contains hidden or 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 <iostream> | |
#include <numeric> | |
#include <algorithm> | |
#include <tuple> | |
#include <sstream> | |
#include <functional> | |
/* const correctness and pass by value vs const ref, move semantics | |
left as an exercise to the reader. | |
iterator range API prevents a flatmap as the flatmapped function | |
could not either return a value or a range. | |
(would return the paste-the-end iterator of an output range)*/ | |
template<typename Op, template<typename, typename> class Transducer > | |
struct transducer_helper { | |
Op op; | |
transducer_helper(Op o):op(o){} | |
template <typename Reducer> | |
Transducer<Op, Reducer> operator()(Reducer r) | |
{return Transducer<Op, Reducer>(op, r);} | |
}; | |
template <typename Op, typename Reducer> | |
struct transducer_base { | |
Op op; | |
Reducer reducer; | |
transducer_base(Op o, Reducer r): op(o), reducer(r){} | |
}; | |
template <typename Op, typename Reducer> | |
struct map_transducer : transducer_base<Op, Reducer> { | |
using transducer_base<Op, Reducer>::transducer_base; | |
template<typename Result, typename Input> | |
Result operator()(Result r, Input data) | |
{ return this->reducer(r, this->op(data));} | |
}; | |
template <typename Op> | |
transducer_helper<Op, map_transducer> map(Op const& op) | |
{ return transducer_helper<Op, map_transducer>(op); } | |
template <typename Op, typename Reducer> | |
struct filter_transducer : transducer_base<Op, Reducer>{ | |
using transducer_base<Op, Reducer>::transducer_base; | |
template<typename Result, typename Input> | |
Result operator()(Result r, Input data) | |
{ return this->op(data) ? this->reducer(r, data) : r ;} | |
}; | |
template <typename Op> | |
transducer_helper<Op, filter_transducer> filter(Op const& op) | |
{ return transducer_helper<Op, filter_transducer>(op); } | |
// We will want to compose the transducers | |
template<typename... Fn> struct composer; | |
template<> struct composer<> { | |
template<typename Data> Data operator()(Data d){ return d; } | |
}; | |
template<typename F0, typename... Fn> | |
struct composer<F0, Fn...> : private composer<Fn...> { | |
F0 f; | |
composer(F0 f0, Fn const&... fn): composer<Fn...>(fn...), f(f0){} | |
template<typename Data> auto operator()(Data d)->decltype(f(composer<Fn...>::operator()(d))) | |
{ return f(composer<Fn...>::operator()(d)); } | |
}; | |
template <typename... Fn> | |
composer<Fn...> comp(Fn const&... fn) | |
{ return composer<Fn...>(fn...); } | |
struct compose_isofunctor { | |
template <typename R, typename... Args> | |
std::function<R(Args...)> operator()(R f1(Args...), R f2(Args...)) const { | |
std::function<R(Args...)> res=comp(f1, f2); | |
return res; } | |
}; | |
template <typename F> | |
struct compose_functions { | |
F operator()(F f1, F f2) const { | |
F res=comp(f1, f2); | |
return res; } | |
}; | |
//using identity = composer<>; | |
template < typename Transducer, typename Reducer, typename Init, typename In> | |
Init transduce (Transducer xform, Reducer f, Init res, In b, In e) | |
{ return std::accumulate(b, e, res, xform(f)); } | |
// the flatmap Op takes two args, the data and an output iter | |
// (and returns the past-the-end output iter) | |
template <typename Op, typename Reducer> | |
struct flatmap_transducer : transducer_base<Op, Reducer>{ | |
using transducer_base<Op, Reducer>::transducer_base; | |
template<typename Result, typename Input> | |
Result operator()(Result r, Input data){ | |
return (this->op(data, make_reducing_output_iterator(this->reducer, r))).res; | |
} | |
}; | |
template <typename Op> | |
transducer_helper<Op, flatmap_transducer> flatmap(Op const& op) | |
{ return transducer_helper<Op, flatmap_transducer>(op); } |
This file contains hidden or 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 <tuple> | |
#include <sstream> | |
struct lexical_reader { | |
std::string data; | |
lexical_reader(std::string str):data(str){} | |
lexical_reader(char const* str):data(str){} | |
template<typename V> | |
lexical_reader(V d){ std::ostringstream oss; oss<<d; data= oss.str();} | |
template<class E> void operator()(E& elt){ | |
std::istringstream iss(data); | |
iss >> elt; | |
} | |
}; | |
template<int... Is> struct seq {}; | |
template<int N, int... Is> struct gen_seq : gen_seq<N-1, N-1, Is...> {}; | |
template<int... Is> struct gen_seq<0, Is...> : seq<Is...> {}; | |
template<int N, class T, class F> | |
void apply_one(T& p, F func){ func( std::get<N>(p)); } | |
template<class T, class F, int... Is> | |
void apply(T& p, int index, F func, seq<Is...>){ | |
using FT = void(T&, F); | |
static constexpr FT* arr[] = { &apply_one<Is, T, F>... }; | |
arr[index](p, func); | |
} | |
template<class T, class F> | |
void apply(T& p, int index, F func) | |
{ apply(p, index, func, gen_seq<std::tuple_size<T>::value>()); } | |
template<typename T> struct tuple_reader{ | |
template <typename Reducer> struct tuple_reader_transducer { | |
T t; | |
std::size_t i; | |
Reducer reducer; | |
tuple_reader_transducer(Reducer r):i(0), reducer(r){} | |
template<typename Result, typename Input> | |
Result operator()(Result r, Input data) { | |
apply(t, i, lexical_reader(data)); ++i; | |
if(i == std::tuple_size<T>::value ){ i= 0; } | |
return i ? r : this->reducer(r, t) ; | |
} | |
}; | |
template <typename Reducer> | |
tuple_reader_transducer<Reducer> operator()(Reducer r) const | |
{ return tuple_reader_transducer<Reducer>(r); } | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment