Skip to content

Instantly share code, notes, and snippets.

@edalorzo
Last active December 14, 2015 02:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save edalorzo/5015143 to your computer and use it in GitHub Desktop.
Save edalorzo/5015143 to your computer and use it in GitHub Desktop.
C# Infinite Streams
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CodeMasters
{
class Program
{
//creates an infinite stream of numbers
static Stream<int> from(int n)
{
return new Cons<int>(n, () => from(n + 1));
}
//sieve of Erathostenes: infinite sequence of primes
static Stream<int> sieve(Stream<int> source)
{
return new Cons<int>(source.head(), ()=> sieve(source.tail().filter(n => n % source.head() != 0)));
}
static void Main(string[] args)
{
//prints odd natural numbers under 100
from(0).takeWhile(n => n <= 100)
.filter(n => n % 2 != 0)
.forEach(n => Console.Write(n + " "));
Console.WriteLine();
Console.WriteLine();
//prints prime numbers under 50
Stream<int> primes = sieve(from(2));
primes.takeWhile(n => n < 50)
//.filter(n => n % 2 != 0)
.forEach(n => Console.Write(n + " "));
Console.ReadLine();
}
}
interface Stream<T>
{
T head();
Stream<T> tail();
bool isEmpty();
Stream<T> takeWhile(Predicate<T> p);
Stream<T> filter(Predicate<T> p);
void forEach(Action<T> consumer);
}
class Empty<T> : Stream<T>
{
public T head() { throw new Exception("Stream is emtpy"); }
public Stream<T> tail() { throw new Exception("Stream is emtpy"); }
public bool isEmpty() { return true; }
public Stream<T> takeWhile(Predicate<T> p) { throw new Exception("Stream is emtpy"); }
public Stream<T> filter(Predicate<T> p) { throw new Exception("Stream is emtpy"); }
public void forEach(Action<T> consumer) { throw new Exception("Stream is emtpy"); }
}
class Cons<T> : Stream<T>
{
private readonly T _head;
private readonly Func<Stream<T>> _tail;
public Cons(T head, Func<Stream<T>> tail)
{
this._head = head;
this._tail = tail;
}
public T head()
{
return this._head;
}
public Stream<T> tail()
{
//evaluates thunk
return this._tail();
}
public bool isEmpty()
{
return false;
}
public Stream<T> takeWhile(Predicate<T> p)
{
return takeWhile(p, this);
}
public Stream<T> filter(Predicate<T> p)
{
return filter(p, this);
}
public void forEach(Action<T> consumer)
{
forEach(consumer, this);
}
private static Stream<T> takeWhile<T>(Predicate<T> p, Stream<T> stream)
{
if (stream.isEmpty() || !p(stream.head()))
{
return new Empty<T>();
}
return new Cons<T>(stream.head(), () => takeWhile(p, stream.tail()));
}
private static Stream<T> filter<T>(Predicate<T> p, Stream<T> stream)
{
if (stream.isEmpty())
{
return new Empty<T>();
}
if (!p(stream.head()))
{
return filter(p, stream.tail());
}
return new Cons<T>(stream.head(), () => filter(p, stream.tail()));
}
private static void forEach<T>(Action<T> consumer, Stream<T> stream)
{
while (!stream.isEmpty())
{
consumer(stream.head());
stream = stream.tail();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment