Skip to content

Instantly share code, notes, and snippets.

@b0urb4k1
Last active August 29, 2015 14:25
Show Gist options
  • Save b0urb4k1/c03fc7c2e9b690ee3d94 to your computer and use it in GitHub Desktop.
Save b0urb4k1/c03fc7c2e9b690ee3d94 to your computer and use it in GitHub Desktop.
using System.Reactive.Subjects;
using System.Reactive.Linq;
using System;
using LanguageExt;
using static LanguageExt.Prelude;
using static Shock.Strategies;
using System.Collections.Generic;
using static Shock.BusinessLogic;
using System.Linq;
namespace Shock
{
#region Variable
public sealed class Variable<T> : ISubject<T>, IDisposable
{
private BehaviorSubject<T> _subject;
private Action _onDispose;
private Variable() {}
public static Variable<T> make(BehaviorSubject<T> subject) => new Variable<T>() {_subject = subject };
public IDisposable Subscribe(IObserver<T> observer) => _subject.Subscribe(observer);
public void OnCompleted() => _subject.OnCompleted();
public void OnError(Exception error) => _subject.OnError(error);
public void OnNext(T value) => _subject.OnNext(value);
public static Variable<T> make(Action onDispose) =>
new Variable<T>()
{ _subject = new BehaviorSubject<T>(default(T))
, _onDispose = onDispose
};
public static Variable<T> make(T value, Action onDispose) =>
new Variable<T>()
{ _subject = new BehaviorSubject<T>(value)
, _onDispose = onDispose
};
public void Dispose()
{
if (_onDispose != null)
_onDispose();
_subject.Dispose();
}
public T Value { get { return _subject.Value; } set { _subject.OnNext(value); } }
}
#endregion
#region Combinder
public static class Combiner
{
public static IObservable<Tuple<T1, T2>> and<T1, T2, T3>
( this IObservable<T1> o1
, Tuple<Func<IObservable<T1>, IObservable<T2>, IObservable<Tuple<T1, T2>>>, Func<IObservable<Tuple<T1, T2>>, IObservable<T3>, IObservable<Tuple<T1, T2, T3>>>> fun
, IObservable<T2> o2
) => fun.Item1(o1, o2);
public static IObservable<Tuple<T1, T2, T3>> and<T1, T2, T3>
(this IObservable<Tuple<T1, T2>> o1
, Tuple<Func<IObservable<T1>, IObservable<T2>, IObservable<Tuple<T1, T2>>>, Func<IObservable<Tuple<T1, T2>>, IObservable<T3>, IObservable<Tuple<T1, T2, T3>>>> fun
, IObservable<T3> o2
) => fun.Item2(o1, o2);
public static IObservable<T3> then<T1, T2, T3>(this IObservable<Tuple<T1, T2>> o, Func<Tuple<T1, T2>, T3> fun) =>
o.Select(v => { return fun(v); });
public static IObservable<T4> then<T1, T2, T3, T4>(this IObservable<Tuple<T1, T2, T3>> o, Func<Tuple<T1, T2, T3>, T4> fun) =>
o.Select(v => { return fun(v); });
public static IObservable<T3> then<T1, T2, T3>(this IObservable<Tuple<T1, T2>> o, Func<T1, T2, T3> fun) =>
o.then(tuplize(fun));
public static IObservable<T4> then<T1, T2, T3, T4>(this IObservable<Tuple<T1, T2, T3>> o, Func<T1, T2, T3, T4> fun) =>
o.then(tuplize(fun));
public static IDisposable assign<T>(this IObservable<T> o, ISubject<T> b) => o.Subscribe(b.OnNext);
public static Func<Tuple<T1, T2>, T3> tuplize<T1, T2, T3>(Func<T1, T2, T3> fun) =>
t => fun(t.Item1, t.Item2);
public static Func<Tuple<T1, T2, T3>, T4> tuplize<T1, T2, T3, T4>(Func<T1, T2, T3, T4> fun) =>
t => fun(t.Item1, t.Item2, t.Item3);
public static IDisposable then<T>(this Variable<T> v, Action<T> a) => v.Skip(1).Subscribe(a);
}
#endregion
#region NoBuffer
class NoBuffer<T1, T2> : IObservable<Tuple<T1, T2>>, IDisposable
{
readonly IObservable<T1> _observer1;
readonly IObservable<T2> _observer2;
Option<T1> _optional1;
Option<T2> _optional2;
readonly IDisposable _subscription1;
readonly IDisposable _subscription2;
readonly Subject<Tuple<T1, T2>> _subject = new Subject<Tuple<T1, T2>>();
void OnT1(T1 value) =>
match
( _optional2
, Some: v =>
{
_optional2 = Option<T2>.None;
_subject.OnNext(tuple(value, v));
}
, None: () => _optional1 = value
);
void OnT2(T2 value) =>
match
( _optional1
, Some: v =>
{
_optional1 = Option<T1>.None;
_subject.OnNext(tuple(v, value));
}
, None: () => _optional2 = value
);
void OnCompleted() => _subject.OnCompleted();
void OnError(Exception error) => _subject.OnError(error);
public IDisposable Subscribe(IObserver<Tuple<T1, T2>> observer) => _subject.Subscribe(observer);
public NoBuffer(IObservable<T1> o1, IObservable<T2> o2)
{
_observer1 = o1;
_observer2 = o2;
_subscription1 = _observer1.Subscribe(OnT1, OnError, OnCompleted);
_subscription2 = _observer2.Subscribe(OnT2, OnError, OnCompleted);
}
public void Dispose()
{
_subscription1.Dispose();
_subscription2.Dispose();
_subject.Dispose();
}
}
#endregion
#region Strategies
public static class Strategies
{
public static Tuple<Func<IObservable<T1>, IObservable<T2>, IObservable<Tuple<T1, T2>>>, Func<IObservable<Tuple<T1, T2>>, IObservable<T3>, IObservable<Tuple<T1, T2, T3>>>> _buffer<T1, T2, T3>() =>
Tuple.Create<Func<IObservable<T1>, IObservable<T2>, IObservable<Tuple<T1, T2>>>, Func<IObservable<Tuple<T1, T2>>, IObservable<T3>, IObservable<Tuple<T1, T2, T3>>>>
( (o1, o2) => o1.CombineLatest(o2, (v1, v2) => tuple(v1, v2))
, (o1, o2) => o1.CombineLatest(o2, (t, v) => tuple(t.Item1, t.Item2, v))
);
public static Tuple<Func<IObservable<T1>, IObservable<T2>, IObservable<Tuple<T1, T2>>>, Func<IObservable<Tuple<T1, T2>>, IObservable<T3>, IObservable<Tuple<T1, T2, T3>>>> _consume<T1, T2, T3>() =>
Tuple.Create<Func<IObservable<T1>, IObservable<T2>, IObservable<Tuple<T1, T2>>>, Func<IObservable<Tuple<T1, T2>>, IObservable<T3>, IObservable<Tuple<T1, T2, T3>>>>
( (o1, o2) => new NoBuffer<T1, T2>(o1, o2)
, (o1, o2) => { throw new NotImplementedException(); }
);
}
#endregion
#region Environment
public class Environment<T> : IDisposable
{
private readonly Dictionary<string, Variable<T>> _dictionaryVariables = new Dictionary<string, Variable<T>>();
private readonly Dictionary<string, T> _dictionary = new Dictionary<string, T>();
public Environment(Dictionary<string, T> dictionary)
{
_dictionary = dictionary;
}
public Variable<T> GetOrCreate(string key) => getOrCreate(key, default(T));
public Variable<T> getOrCreate(string key, T value)
{
if (_dictionaryVariables.ContainsKey(key) == false)
{
_dictionaryVariables[key] = Variable<T>.make
( () =>
{ if (_dictionary.ContainsKey(key))
_dictionary.Remove(key)
; if (_dictionaryVariables.ContainsKey(key))
_dictionaryVariables.Remove(key);
});
_dictionaryVariables[key].Subscribe(v => _dictionary[key] = v);
}
return _dictionaryVariables[key];
}
#endregion
public void Dispose()
{
var list = new List<Variable<T>>();
foreach (var k in _dictionaryVariables)
list.Add(k.Value);
list.ForEach(v => v.Dispose());
}
public T this[string key] => _dictionary[key];
}
#region BusinessLogic
public static class BusinessLogic
{
public static int Multiply(int x, int y) => x * y;
public static int Add3(int x, int y, int z) => x + y + z;
}
#endregion
class Program
{
public static void Main(string[] args)
{
#region data
var dictionary = new Dictionary<string, int>();
dictionary.Add("x", 0);
dictionary.Add("y", 0);
dictionary.Add("z", 0);
dictionary.Add("v", 0);
dictionary.Add("sum", 0);
dictionary.Add("endValue", 0);
#endregion
using (var env = new Environment<int>(dictionary))
{
#region variables
var x = env.GetOrCreate("x");
var y = env.GetOrCreate("y");
var z = env.GetOrCreate("z");
var v = env.GetOrCreate("v");
var sum = env.GetOrCreate("sum");
var endValue = env.GetOrCreate("endValue"); ;
#endregion
#region strategies
var consume = _consume<int, int, int>();
var buffer = _buffer<int, int, int>();
#endregion
using (x.and(buffer, y).and(buffer, z).then(Add3).assign(sum))
using (sum.and(buffer, v).then(Multiply).assign(endValue))
using (endValue.then(Console.WriteLine))
{
x.Value = 1;
y.Value = 2;
z.Value = 3;
v.Value = 4;
//z.Value = 5;
//v.Value = 6;
}
Console.WriteLine(env["sum"]);
Console.WriteLine(env["endValue"]);
}
System.Console.ReadKey();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment