Skip to content

Instantly share code, notes, and snippets.

@JohnNilsson
Created April 14, 2014 07:21
Show Gist options
  • Save JohnNilsson/10623861 to your computer and use it in GitHub Desktop.
Save JohnNilsson/10623861 to your computer and use it in GitHub Desktop.
Reading Push Pull FRP in C#
public static class ComparableExtensions
{
public static bool IsAfter<T>(this T c1, T c2) where T:IComparable<T>
{
return Comparer<T>.Default.Compare(c1,c2) > 0;
}
public static T Min<T>(this T c1, T c2) where T:IComparable<T>
{
return (c1.CompareTo(c2) < 0) ? c1 : c2;
}
public static T Max<T>(this T c1, T c2) where T : IComparable<T>
{
return (c1.CompareTo(c2) > 0) ? c1 : c2;
}
}
/// <summary>
/// Some FRP theory from Conal Eliot ( http://conal.net/papers/push-pull-frp/push-pull-frp.pdf )
/// </summary>
internal static class FRPSemantics<TTime> where TTime : IComparable<TTime>
{
// 2 Functional Reactive Programming
// Behavior<TValue> = Func<TTime,TValue>
public delegate T Behavior<T>(TTime t);
// EventSource<TValue> = IEnumerable<Tuple<TTime,TValue>>
static TTime NegativeInfinity;
static TTime PositiveInfinity;
public struct Event<T>
{
public readonly TTime Time;
public readonly T Value;
public Event(TTime time, T value)
{
this.Time = time;
this.Value = value;
}
}
// 2.1 Behaviors
static Behavior<TTime> Time = t => t;
// 2.1.1 Functor
// Compare Observable.CombineLatest
static Func<Behavior<TArg1>, Behavior<TResult>> Lift<TArg1, TResult>(Func<TArg1, TResult> f)
{
return (b1) => t => f(b1(t));
}
static Func<Behavior<TArg1>, Behavior<TArg2>, Behavior<TResult>> Lift<TArg1, TArg2, TResult>(Func<TArg1, TArg2, TResult> f)
{
return (b1, b2) => t => f(b1(t), b2(t));
}
//...
internal static class BehaviorFunctor
{
internal static Behavior<TResult> FMap<TArg, TResult>(Behavior<TArg> b, Func<TArg, TResult> f)
{
return Lift(f)(b);
}
}
// 2.1.2 Applicative Functor
internal static class BehaviorApplicativeFunctor
{
static Behavior<T> Pure<T>(T value)
{
return _ => value;
}
static Behavior<TResult> Ap<TArg, TResult>(Behavior<TArg> b, Behavior<Func<TArg, TResult>> f)
{
return t => f(t)(b(t));
}
}
static class Semantic
{
public static class Functor<T>
{
static Func<T,TResult> FMap<TArg, TResult>(Func<T, TArg> f, Func<TArg, TResult> g)
{
return t => g(f(t));
}
}
public static class ApplicativeFunctor<T>
{
static Func<T, TResult> Pure<TResult>(TResult value)
{
return _ => value;
}
static Func<T, TResult> Ap<TArg, TResult>(Func<T, TArg> f, Func<T, Func<TArg,TResult>> g)
{
return t => g(t)(f(t));
}
}
}
// 2.2 Events
// 2.2.1 Monoid
static class EventMergeMonoid<T>
{
public static IEnumerable<Event<T>> MEmpty = Enumerable.Empty<Event<T>>();
public static IEnumerable<Event<T>> MAppend(IEnumerable<Event<T>> e1, IEnumerable<Event<T>> e2)
{
using (var e1s = e1.GetEnumerator())
using (var e2s = e2.GetEnumerator())
return Merge(e1s, e2s);
}
private static IEnumerable<Event<T>> Merge(IEnumerator<Event<T>> es1, IEnumerator<Event<T>> es2)
{
Event<T>? e1, e2;
while(true)
{
e1 = es1.MoveNext() ? es1.Current : (Event<T>?)null;
e2 = es2.MoveNext() ? es2.Current : (Event<T>?)null;
if (e1.HasValue && e2.HasValue)
{
if (e1.Value.Time.IsAfter(e2.Value.Time))
{
yield return e2.Value;
yield return e1.Value;
}
else
{
yield return e1.Value;
yield return e2.Value;
}
}
else if (e1.HasValue)
yield return e1.Value;
else if (e2.HasValue)
yield return e2.Value;
else
yield break;
}
}
}
// 2.2.2 Event functor
static class EventFunctor
{
public static IEnumerable<Event<TResult>> FMap<TArg,TResult>(IEnumerable<Event<TArg>> es, Func<TArg,TResult> f)
{
return es.Select(e => new Event<TResult>(e.Time, f(e.Value)));
}
}
// 2.2.3 Event Monad
static class EventMonad
{
public static IEnumerable<Event<T>> Unit<T>(T value)
{
yield return new Event<T>(NegativeInfinity, value);
}
public static IEnumerable<Event<T>> Join<T>(IEnumerable<Event<IEnumerable<Event<T>>>> es)
{
return es.Select(DelayOccs).Aggregate(EventMergeMonoid<T>.MEmpty, EventMergeMonoid<T>.MAppend);
}
private static IEnumerable<Event<T>> DelayOccs<T>(Event<IEnumerable<Event<T>>> es)
{
return from e in es.Value
select new Event<T>(es.Time.Max(e.Time), e.Value);
}
}
// 2.3 Combining behaviors and events
static Behavior<T> Switcher<T>(Behavior<T> b0, IEnumerable<Event<Behavior<T>>> es)
{
return t =>
es.TakeWhile(e => t.IsAfter(e.Time)).Select(e => e.Value)
.DefaultIfEmpty(b0)
.LastOrDefault()(t);
}
static Behavior<T> Stepper<T>(T v0, IEnumerable<Event<T>> es)
{
return t =>
es.TakeWhile(e => t.IsAfter(e.Time)).Select(e => e.Value)
.DefaultIfEmpty(v0)
.LastOrDefault();
}
// 4. Future
struct FutureTime
{
TTime LowerBound;
Task<TTime> Time;
}
// 5.2 Reactive values
delegate T Reactive<T>(TTime t);
//static Reactive<T> Reactive<T>(T value, IEnumerable<Event<T>> events)
//{
// var reactive = Stepper(value, events);
// return t => reactive(t);
//}
// 5.3 Time functions
delegate T Fun<TTime,T>(TTime t);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment