Last active
August 29, 2015 14:03
-
-
Save maxgherman/04662d0f263c0f9390ab to your computer and use it in GitHub Desktop.
Haskell / Scala Infinite Streams in C#
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
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace ConsoleApplication | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
Stream<int> s = null; | |
// stream of zeroes | |
s = new Stream<int>(0, () => s); | |
Print(s); | |
// stream of 0 1 | |
s = 0 * new Stream<int>(1, () => s); | |
Print(s); | |
// 0 1 | |
s = 0 * new Stream<int>(1); | |
Print(s); | |
// 0 1 Empty | |
s = 0 * (1 * Stream<int>.Empty); | |
Print(s); | |
// memoizaion | |
s = new Stream<int>(() => 0, n => | |
{ | |
Console.Write("Eval : {0} ", n); | |
return n + 1; | |
}); | |
Print(s); | |
Print(s); | |
// fibonacci sequence with tuples | |
var s1 = (new Tuple<int, int>(0, 0) * new Stream<Tuple<int, int>>(() => new Tuple<int, int>(1, 0), | |
pair => new Tuple<int, int>(pair.Item1 + pair.Item2, pair.Item1))).Select(item => item.Head.Value.Item1); | |
Print(s1); | |
// fibonacci sequence with dynamic | |
s1 = ((new { Item1 = 0, Item2 = 0 }) * new Stream<dynamic>(() => new { Item1 = 1, Item2 = 0 }, | |
pair => new { Item1 = pair.Item1 + pair.Item2, Item2 = pair.Item1 })).Select(item => (int)item.Head.Value.Item1); | |
Print(s1); | |
// fibonacci sequence with Func | |
Func<int, int, Stream<int>> fibonacci = null; | |
fibonacci = (h, n) => new Stream<int>(() => h, () => fibonacci(n, h + n)); | |
s = 0 * fibonacci(1, 1); | |
Print(s); | |
// fibonacci sequence with Zip | |
s = 0 * new Stream<int>(1); | |
Func<Stream<int>, Stream<int>> fibonacci2 = null; | |
fibonacci2 = stream => | |
{ | |
var filtered = stream.Zip(stream.Tail, (n1, n2) => new Stream<int>(() => n1.Head.Value + n2.Head.Value, (Func<Stream<int>>)null)).First(); | |
return new Stream<int>(stream.Head, () => fibonacci2(stream.Tail.Head * filtered)); | |
}; | |
Print(fibonacci2(s)); | |
// odd numbers enumarable | |
s = new Stream<int>(() => 1, n => n + 1); | |
Print(s.Where(st => st.Head.Value % 2 != 0).Select(item => item.Head.Value)); | |
// odd numbers stream | |
s = new Stream<int>(() => 1, n => n + 2); | |
Print(s); | |
// odd numbers filtered stream | |
s = new Stream<int>(() => 1, n => n + 1); | |
Func<Stream<int>, Stream<int>> filterOdd = null; | |
filterOdd = stream => | |
{ | |
var filtered = stream.Tail.Where(item => item.Head.Value % 2 != 0); | |
return new Stream<int>(stream.Head, () => filterOdd(new Stream<int>(filtered))); | |
}; | |
Print(filterOdd(s)); | |
// square root of 2 ( Newton's method ) | |
var sQ = new Stream<double>(() => 1, x => 0.5 * x + 1 / x); | |
Print(sQ); | |
// unfaithful Eratosthenes sieve | |
s = new Stream<int>(() => 3, n => n + 2); | |
Func<Stream<int>, Stream<int>> sieve = null; | |
sieve = stream => | |
{ | |
var filtered = stream.Tail.Where(item => item.Head.Value % stream.Head.Value != 0); | |
return new Stream<int>(stream.Head, () => sieve(new Stream<int>(filtered))); | |
}; | |
Print(2 * sieve(s)); | |
// Power | |
Func<double, double, Stream<double>> fPow = null; | |
fPow = (x, m) => new Stream<double>(() => x, () => fPow(x * m, m)); | |
Print(fPow(2, 2)); | |
// archtan 0.2, James Gregory: x - x^3/3 + x^5/5 - x^7/7 | |
s = new Stream<int>(() => 3, n => n + 2); | |
Func<double, int, Stream<int>, Stream<double>> fArchtan = null; | |
fArchtan = (x, sign, stream) => | |
{ | |
Func<double> fValue = () => x + sign * fPow(x, x).Skip(stream.Head.Value - 1).First().Head.Value / stream.Head.Value; | |
Func<Stream<double>> fNext = () => fArchtan(fValue(), -1*sign, stream.Tail); | |
return new Stream<double>(x, fNext); | |
}; | |
Print(fArchtan(0.2, -1, s)); | |
// PI, John Machin | |
var v1 = fArchtan(1 / 5.0, -1, s).Skip(20).First().Head.Value; | |
var v2 = fArchtan(1 / 239.0, -1, s).Skip(20).First().Head.Value; | |
Console.WriteLine(4 * (4 * v1 - v2)); | |
Console.ReadKey(); | |
} | |
private static void Print<T>(Stream<T> stream, int? count = 20) | |
{ | |
stream.Take(count.Value).ToList().ForEach(item => Console.Write("{0} ", item.Head.Value)); | |
Console.WriteLine(); | |
Console.WriteLine(); | |
} | |
private static void Print<T>(IEnumerable<T> stream, int? count = 20) | |
{ | |
stream.Take(count.Value).ToList().ForEach(item => Console.Write("{0} ", item)); | |
Console.WriteLine(); | |
Console.WriteLine(); | |
} | |
} | |
public class Stream<T> : IEnumerable<Stream<T>> | |
{ | |
private Lazy<T> lazyValue; | |
private Lazy<Stream<T>> _tail; | |
public virtual Lazy<T> Head { get { return lazyValue; } } | |
public virtual bool IsEmpty { get { return false; } } | |
public virtual Stream<T> Tail | |
{ | |
get | |
{ | |
return _tail == null ? (Stream<T>)null : _tail.Value; | |
} | |
} | |
private Stream() { } | |
public Stream(Lazy<T> value, Func<Stream<T>> tail = null) | |
{ | |
lazyValue = value; | |
_tail = tail == null ? null : new Lazy<Stream<T>>(tail); | |
} | |
public Stream(T value, Func<Stream<T>> tail = null) | |
: this(new Lazy<T>(() => value), tail) | |
{ } | |
public Stream(Func<T> value, Func<Stream<T>> tail = null) | |
: this(new Lazy<T>(value), tail) | |
{ } | |
public Stream(Func<T> value, Func<T, Stream<T>> tail = null) | |
: this(new Lazy<T>(value), null) | |
{ | |
_tail = tail == null ? null : new Lazy<Stream<T>>(() => tail(Head.Value)); | |
} | |
public Stream(Func<T> value, Func<T, T> evaluator = null) | |
: this(new Lazy<T>(value), null) | |
{ | |
if (evaluator != null) | |
{ | |
Func<Stream<T>> f = null; | |
f = () => new Stream<T>(() => evaluator(Head.Value), evaluator); | |
_tail = new Lazy<Stream<T>>(f); | |
} | |
} | |
public Stream(IEnumerable<Stream<T>> sequence) | |
{ | |
lazyValue = new Lazy<T>(() => sequence.First().Head.Value); | |
_tail = new Lazy<Stream<T>>(() => new SequenceStream<T>(sequence.Skip(1))); | |
} | |
public static Stream<T> Empty { get { return new EmptyStream<T>(); } } | |
public static Stream<T> operator *(T value, Stream<T> stream) | |
{ | |
if (stream.IsEmpty) return new Stream<T>(value, (Func<Stream<T>>)null); | |
return (() => value) * stream; | |
} | |
public static Stream<T> operator *(Lazy<T> value, Stream<T> stream) | |
{ | |
if (stream.IsEmpty) return new Stream<T>(value, (Func<Stream<T>>)null); | |
return new Stream<T>(value, () => stream); | |
} | |
public static Stream<T> operator *(Func<T> value, Stream<T> stream) | |
{ | |
if (stream.IsEmpty) return new Stream<T>(value, (Func<Stream<T>>)null); | |
return new Stream<T>(value, () => stream); | |
} | |
public virtual IEnumerator<Stream<T>> GetEnumerator() | |
{ | |
var stream = this; | |
while (stream != null && !stream.IsEmpty) | |
{ | |
yield return stream; | |
if (stream.Tail == null) yield break; | |
stream = stream.Tail; | |
} | |
} | |
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() | |
{ | |
return this.GetEnumerator(); | |
} | |
class EmptyStream<T> : Stream<T> | |
{ | |
public override Lazy<T> Head | |
{ | |
get { throw new Exception("Empty stream"); } | |
} | |
public override Stream<T> Tail | |
{ | |
get { throw new Exception("Empty stream"); } | |
} | |
public override IEnumerator<Stream<T>> GetEnumerator() | |
{ | |
throw new Exception("Empty stream"); | |
} | |
public override bool IsEmpty | |
{ | |
get { return true; } | |
} | |
} | |
class SequenceStream<T> : Stream<T> | |
{ | |
private readonly IEnumerable<Stream<T>> _sequence; | |
public override Lazy<T> Head | |
{ | |
get { return _sequence.First().Head; } | |
} | |
public override Stream<T> Tail | |
{ | |
get { return _sequence.Skip(1).First().Tail; } | |
} | |
public override IEnumerator<Stream<T>> GetEnumerator() | |
{ | |
return _sequence.GetEnumerator(); | |
} | |
public override bool IsEmpty | |
{ | |
get { return !_sequence.Any(); } | |
} | |
public SequenceStream(IEnumerable<Stream<T>> sequence) | |
{ | |
this._sequence = sequence; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment