Skip to content

Instantly share code, notes, and snippets.

@ldiego08
Last active December 14, 2015 02:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ldiego08/5016369 to your computer and use it in GitHub Desktop.
Save ldiego08/5016369 to your computer and use it in GitHub Desktop.
Example of infinite streams of numbers and the Sieve of Erathostenes using functional programming in C#. Adapted from an example written by Edwin Dalorzo (https://gist.github.com/edalorzo/5015143)
using System;
namespace Codenough.Samples
{
public class DeferredStream<TValue> : IStream<TValue>
{
private readonly TValue head;
private readonly Func<IStream<TValue>> tail;
public DeferredStream(TValue head, Func<IStream<TValue>> tail)
{
this.head = head;
this.tail = tail;
}
public TValue Head
{
get { return this.head; }
}
public IStream<TValue> Tail
{
get { return this.tail(); }
}
}
}
using System;
namespace Codenough.Samples
{
public class EmptyStream<TValue> : IStream<TValue>
{
public TValue Head
{
get { throw new InvalidOperationException("The stream is empty."); }
}
public IStream<TValue> Tail
{
get { throw new InvalidOperationException("The stream is empty."); }
}
public bool IsEmpty
{
get { return true; }
}
}
}
using System;
namespace Codenough.Samples
{
public interface IStream<TValue>
{
TValue Head { get; }
IStream<TValue> Tail { get; }
bool IsEmpty { get; }
}
}
using System;
namespace Codenough.Samples
{
public static class Program
{
public static void Main(string[] args)
{
CreateInfiniteStreamFrom(0)
.TakeWhile(number => number <= 100)
.Where(number => number % 2 != 0)
.ForEach(number => Console.WriteLine(number));
Console.WriteLine();
Console.WriteLine();
var infiniteNumberStream = CreateInfiniteStreamFrom(2);
var primeNumbers = CreateSieveOfErathostenesFor(infiniteNumberStream);
primeNumbers
.TakeWhile(number => number < 50)
.ForEach(number => Print(number));
Console.ReadLine();
}
private static IFilterableStream<int> CreateInfiniteStreamFrom(int start)
{
return new DeferredStream<int>(start, () => CreateInfiniteStreamFrom(start + 1));
}
private static IFilterableStream<int> CreateSieveOfErathostenesFor(IFilterableStream<int> source)
{
Func<IFilterableStream<int>> sieveEvaluator = () => CreateSieveOfErathostenesFor(source.Tail.Where(number => number % source.Head != 0));
return new DeferredStream<int>(source.Head, sieveEvaluator);
}
private static void Print(int number)
{
Console.WriteLine(number);
}
}
}
using System;
namespace Codenough.Samples
{
public static class StreamExtensions
{
public static IStream<TValue> TakeWhile<TValue>(this IStream<TValue> source, Predicate<TValue> predicate)
{
if (source.IsEmpty)
{
throw new InvalidOperationException("The stream is empty.");
}
return TakeWhile(predicate, source);
}
public static IStream<TValue> Where<TValue>(this IStream<TValue> source, Predicate<TValue> predicate)
{
if (source.IsEmpty)
{
throw new InvalidOperationException("The stream is empty.");
}
return Where(predicate, source);
}
public static void ForEach<TValue>(this IStream<TValue> source, Action<TValue> consumer)
{
if (source.IsEmpty)
{
throw new InvalidOperationException("The stream is empty.");
}
ForEach(consumer, source);
}
private static IStream<TValue> TakeWhile<TValue>(Predicate<TValue> predicate, IStream<TValue> stream)
{
if (stream.IsEmpty || !predicate(stream.Head))
{
return new EmptyStream<TValue>();
}
else
{
return new DeferredStream<TValue>(stream.Head, () => TakeWhile(predicate, stream.Tail));
}
}
private static IStream<TValue> Where<TValue>(Predicate<TValue> predicate, IStream<TValue> stream)
{
if (stream.IsEmpty)
{
return new EmptyStream<TValue>();
}
else if (!predicate(stream.Head))
{
return Where(predicate, stream.Tail);
}
else
{
return new DeferredStream<TValue>(stream.Head, () => Where(predicate, stream.Tail));
}
}
private static void ForEach<TValue>(Action<TValue> consumer, IStream<TValue> 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