Sunday, February 20, 2011

Functional Reactive Programming(3)

I am studying Functional Reactive Programming(FRP).
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