// A possible implementation of lazy streams in C++ // // This code is pretty much self-explanatory. If you've ever seen a similar // thing implemented in Scheme, that is. // // Mauro Persano - m at fzort dot org // // GPL v2 // Revision history: // // 2006-03-07 19:23 Unleashed unto an unsuspecting world. // 2006-03-08 08:12 Minor clean-up. // 2006-03-10 12:22 Eliminated some useless heap-allocation // (thanks bicoherent). //--------------------------------------------------------------------------- // // s t r e a m // struct stream; struct abstract_stream { virtual ~abstract_stream() { } stream *nth(int n); virtual stream *force() = 0; }; struct stream : abstract_stream { int car; abstract_stream *cdr; stream(int car_ = 0, abstract_stream *cdr_ = 0) : car(car_), cdr(cdr_) { } virtual ~stream() { if (cdr) delete cdr; } virtual stream *force() { return this; } }; stream * abstract_stream::nth(int n) { stream *l = force(); return n == 0 ? l : l->cdr->nth(n - 1); } //--------------------------------------------------------------------------- // // p r o m i s e // struct promise : abstract_stream { bool evaled; stream *value; promise() : evaled(false), value(0) { } virtual ~promise() { if (value) delete value; } virtual stream *force(); virtual stream *eval() = 0; }; stream * promise::force() { if (!evaled) value = eval(), evaled = true; return value; } template struct promise0 : promise { virtual stream *eval() { return new T; } }; template struct promise1 : promise { promise1(const Ta& a_) : a(a_) { } virtual stream *eval() { return new T(a); } Ta a; }; template struct promise2 : promise { promise2(const Ta& a_, const Tb& b_) : a(a_), b(b_) { } virtual stream *eval() { return new T(a, b); } Ta a; Tb b; }; template struct promise3 : promise { promise3(const Ta& a_, const Tb& b_, const Tc& c_) : a(a_), b(b_), c(c_) { } virtual stream *eval() { return new T(a, b, c); } Ta a; Tb b; Tc c; }; template promise3 * delay(const Ta& a_, const Tb& b_, const Tc& c_) { return new promise3(a_, b_, c_); } template promise2 * delay(const Ta& a_, const Tb& b_) { return new promise2(a_, b_); } template promise1 * delay(const Ta& a_) { return new promise1(a_); } template promise0 * delay() { return new promise0; } //--------------------------------------------------------------------------- // // f i l t e r // template struct predicate { virtual ~predicate() { } bool operator()(int a) const { return dynamic_cast(*this)(a); } }; template struct filter : stream { filter(const P& p_, abstract_stream *l_); const P& p; }; template filter

::filter(const P& p_, abstract_stream *l_) : p(p_) { stream *l; while (l = l_->force(), !p_(l->car)) l_ = l->cdr; car = l->car; cdr = delay(p_, l->cdr); } //--------------------------------------------------------------------------- // // s i e v e // struct not_divisible_by : predicate { int x; not_divisible_by(int x_) : x(x_) { } bool operator()(int a) const { return a%x != 0; } }; struct sieve : stream { sieve(abstract_stream *s_); const not_divisible_by p; filter f; }; sieve::sieve(abstract_stream *s_) : stream(s_->force()->car) , p(not_divisible_by(car)) , f(filter(p, s_->force()->cdr)) { cdr = delay(&f); } struct add : stream { add(abstract_stream *s1_, abstract_stream *s2_); }; add::add(abstract_stream *s1_, abstract_stream *s2_) { stream *s1 = s1_->force(); stream *s2 = s2_->force(); car = s1->car + s2->car; cdr = delay(s1->cdr, s2->cdr); } struct ones : stream { ones() : stream(1, delay()) { } }; #include int main(int argc, char *argv[]) { #if 0 // the infinite stream of fibonacci numbers stream fibs(1, new stream(1)); fibs.cdr->force()->cdr = delay(&fibs, fibs.cdr); // this would have looked much nicer: // // fibs = new stream(1, new stream(1, delay(fibs, fibs->cdr))) // // alas, not possible. for (int i = 0; i < 20; i++) std::cout << fibs.nth(i)->car << "\n"; #else // an infinite stream of ones ones onez; // the infinite stream of positive integers stream ints(1); ints.cdr = delay(&onez, &ints); // the infinite stream of prime numbers sieve primes(ints.cdr); for (int i = 0; i < 100; i++) std::cout << primes.nth(i)->car << "\n"; #endif return 0; }