FRP has important 2 concepts, those are Behavior and Event, and I tried to implement Behavior and Event in C#.
The result is following :
public delegate T Behavior<T>(Time t);
public delegate IEnumerable<Tuple<Time, T>> Event<T>();
public static class FrpFunctions
{
public static Behavior<TResult> DollarStar<T, TResult>(Behavior<Func<T, TResult>> ff, Behavior<T> fb)
{
return new Behavior<TResult>(t => ZipWith(HaskellDollar, ff(t), fb(t)));
}
public static TResult HaskellDollar<T, TResult>(Func<T, TResult> f, T v)
{
return f(v);
}
public static TResult ZipWith<T1, T2, TResult>(Func<T1, T2, TResult> op, T1 arg1, T2 arg2)
{
return op(arg1, arg2);
}
public static Behavior<T> Lift0<T>(T v)
{
return new Behavior<T>(e => v);
}
public static Func<Behavior<T>, Behavior<TResult>> Lift1<T, TResult>(Func<T, TResult> f)
{
return b1 => DollarStar(Lift0(f), b1);
}
public static Func<Behavior<T1>, Behavior<T2>, Behavior<TResult>> Lift2<T1, T2, TResult>(Func<T1, T2, TResult> f)
{
return (b1, b2) => DollarStar(Lift1((T1 x) => (Func<T2, TResult>)(y => f(x, y)))(b1), b2);
}
public static Event<T> Choice<T>(Event<T> fe1, Event<T> fe2)
{
public static Event<T> Choice<T>(Event<T> fe1, Event<T> fe2)
{
return new Event<T>(() => Aux(fe1(), fe2()));
}
public static IEnumerable<Tuple<Time, T>> Aux<T>(IEnumerable<Tuple<Time, T>> e1, IEnumerable<Tuple<Time, T>> e2)
{
var en1 = e1.GetEnumerator();
var en2 = e2.GetEnumerator();
bool b1 = en1.MoveNext();
bool b2 = en2.MoveNext();
while(b1 && b2) {
if (en1.Current.Item1.Value < en2.Current.Item1.Value){
yield return en1.Current;
b1 = en1.MoveNext();
}
else{
yield return en2.Current;
b2 = en1.MoveNext();
}
}
while(b1){
yield return en1.Current;
b1 = en1.MoveNext();
}
while(b2){
yield return en2.Current;
b2 = en1.MoveNext();
}
}
public static Event<Tuple<T1, T2>> Snapshot<T1, T2>(Event<T1> fe, Behavior<T2> fb)
{
return new Event<Tuple<T1, T2>>(() => Aux(fe(), t => fb(t)));
}
public static IEnumerable<Tuple<Time, Tuple<T1, T2>>> Aux<T1, T2>(IEnumerable<Tuple<Time, T1>> e1, Func<Time, T2> e2)
{
foreach (var v in e1) {
yield return Tuple.Create(v.Item1, Tuple.Create(v.Item2, e2(v.Item1)));
}
}
public static Event<Unit> Sharp()
{
return When(new Behavior<bool>(t => t.Value == 1));
}
public static Event<Unit> Sharp2()
{
return When(new Behavior<bool>(t => t.Value >= 1));
}
public static Event<Unit> When(Behavior<bool> fb)
{
return new Event<Unit>(() => Up(t => fb(t)));
}
public static IEnumerable<Tuple<Time, Unit>> Up(Func<Time, bool> e2)
{
foreach (var t in Time.Beat()) {
if (e2(t)) {
yield return Tuple.Create(t, new Unit());
}
}
}
}
Where Time is a class and has Beat() static method for returning the instance at regular time intervals.
No comments:
Post a Comment