#include #include #include #include #include using namespace std; #define LAMBDA(x,exp) ([](auto& x){return exp;}) #define LAMVAL(x,exp) ([=](auto& x){return exp;}) #define LAMREF(x,exp) ([&](auto& x){return exp;}) template struct stream { function()> generate; static stream empty_stream() { stream s; s.generate = [](){return nullopt;}; return s; } // casting needed otherwise static optional None() { return (optional)nullopt; } static optional Some(T x) { return (optional)x; } stream& limit(unsigned int n) { auto gen = generate; generate = [=]() mutable { if (n--<1) return None(); else return gen(); }; return *this; } template stream map(function mapfun) { stream su; su.generate = [this,mapfun](){ auto next = generate(); if (!next.has_value()) return (optional)nullopt; else { optional nextu = mapfun(next.value()); return nextu; } }; return su; }//map template stream bind(function(T&)> binder) { stream su; auto nextt = generate(); if (!nextt.has_value()) { su.generate = [](){ return None(); }; return su; } auto currentu = binder(nextt.value()); su.generate = [=]() mutable { optional next; while (1) { next = currentu.generate(); if (next.has_value()) break; nextt = generate(); if (!nextt.has_value()) break; currentu = binder(nextt.value()); }//while return next; }; return su; }//bind stream& filter(function predicate) { auto gen = generate; generate = [=](){ auto next = gen(); while (next.has_value() && !predicate(next.value())) next = gen(); return next; }; return *this; } stream& take_while(function predicate) { auto gen = generate; generate = [=](){ auto next = gen(); if (next.has_value() && predicate(next.value())) return next; else return None(); }; return *this; } stream& until(function predicate) { auto gen = generate; bool islast = true; // this is read-only generate = [=]() mutable { auto next = gen(); if (!next.has_value() || !predicate(next.value())) return next; if (islast) { islast = false; return next; } else return None(); }; return *this; } stream& append(stream& other) { auto gen = generate; generate = [=]{ optional next = gen(); if (next.has_value()) return next; else return other.generate(); }; return *this; } static stream coinduction(T seed, function induct) { stream s; s.generate = [=]() mutable { auto tmp = move(seed); seed = induct(tmp); return tmp; }; return s; } // this only works if T can be copied. static stream seeded_induction(vector& seeds, function&)> gen_next) { stream s; size_t index = 0; s.generate = [&seeds,gen_next,index]() mutable { if (index array_stream(T seeds[], const size_t size) { stream s; size_t index = 0; // seeds cannot be captured by value - will deep copy. s.generate = [=]() mutable { if (index vector_stream(vector& seeds) { stream s; size_t index = 0; s.generate = [index,&seeds]() mutable { if (index finite_stream(vector seeds) { stream s; size_t index = 0; s.generate = [index,seeds=move(seeds)]() mutable { if (index action) { while(1) { auto next = generate(); if (!next.has_value()) break; action(next.value()); }//while }//foreach bool forall(function predicate) { while (1) { auto next = generate(); if (!next.has_value()) return true; else if (!predicate(next.value())) return false; } } bool exists(function predicate) { return !forall([=](T& x){ return !predicate(x); }); } optional find_first(function predicate) { while (1) { auto next = generate(); if (!next.has_value()) return None(); else if (predicate(next.value())) return next; } } optional get_last(function predicate) { auto last = generate(); if (!last.has_value()) return last; while (1) { auto next = generate(); if (!next.has_value()) return last; else last = move(next); } } }; // struct stream uint64_t next_prime(vector& known_primes) { if (known_primes.size()==0) return 2; auto last_prime = known_primes[known_primes.size()-1]; if (last_prime==2) return 3; auto candidates = stream::coinduction(last_prime+2, [](auto x){return x+2;}); return candidates .find_first([&](auto& c){ return stream::vector_stream(known_primes) .take_while([&c](auto& p) {return p <= sqrt(c)+1;}) .forall([&c](auto& p) { return c % p != 0; }); }) .value(); }//next_prime int main() { stream odds = stream::coinduction(1, [](int x) {return x+2;}); odds .limit(50) .filter(LAMBDA(x,x%5==0)) .map(LAMBDA(x,sqrt(x))) .foreach([](auto& x){cout << x << endl;}); vector v{2,4,6,8,10}; //stream s2 = stream::finite_stream(move(v)); stream s2 = stream::finite_stream({1,3,5,7,9}); s2.foreach([](auto& x){cout << x << " ";}); cout << endl; cout << v.size() << endl; int blah[] = {10,20,30}; auto s3 = stream::array_stream(blah,3); s3.foreach([](auto& x){cout << x << " ";}); cout << endl; vector primes{2,3,5,7,11}; auto all_primes = stream::seeded_induction(primes, LAMBDA(kp,next_prime(kp))); // [](auto& kp){return next_prime(kp);}); all_primes //.until([](auto& p){return p>1000;}) .until(LAMBDA(p,p>1000)) .foreach([](auto& x){cout << x << " ";}); cout << endl; cout << "known primes: " << primes.size() << endl; }//main