/// ///Sample the behavior at the time of the event firing. Note that the 'current value' /// of the behavior that's sampled is the value as at the start of the transaction /// before any state changes of the current transaction are applied through 'hold's. /// public Event <TC> Snapshot <TB, TC>(Behavior <TB> b, Func <TA, TB, TC> f) { Event <TA> ev = this; var @out = new EventSink <TC> { SampleNow = () => { Object[] oi = ev.SampleNow(); if (oi != null) { var oo = new Object[oi.Length]; for (int i = 0; i < oo.Length; i++) { oo[i] = f((TA)oi[i], b.SampleNoTrans()); } return(oo); } return(null); } }; Listener l = Listen_( @out.Node, new TransactionHandler <TA> { Run = (trans2, a) => @out.Send(trans2, f(a, b.SampleNoTrans())) }); return(@out.AddCleanup(l)); }
/// ///Unwrap a behavior inside another behavior to give a time-varying behavior implementation. /// public static Behavior <TA> SwitchB <TA>(Behavior <Behavior <TA> > bba) { Func <TA> za = () => bba.SampleNoTrans().SampleNoTrans(); var @out = new EventSink <TA>(); var h = new TransactionHandler <Behavior <TA> >(); h.Run = (trans2, ba) => { // Note: If any switch takes place during a transaction, then the // value().listen will always cause a sample to be fetched from the // one we just switched to. The caller will be fetching our output // using value().listen, and value() throws away all firings except // for the last one. Therefore, anything from the old input behaviour // that might have happened during this transaction will be suppressed. if (h.CurrentListener != null) { h.CurrentListener.Unlisten(); } h.CurrentListener = ba.Value(trans2).Listen( @out.Node, trans2, new TransactionHandler <TA> { Run = (trans3, a) => @out.Send(trans3, a) }, false); }; Listener l1 = bba.Value().Listen_(@out.Node, h); return(@out.AddCleanup(l1).HoldLazy(za)); }
private static Event <TA> SwitchE <TA>(Transaction trans1, Behavior <Event <TA> > bea) { var @out = new EventSink <TA>(); var h2 = new TransactionHandler <TA> { Run = (trans2, a) => @out.Send(trans2, a) }; var h1 = new TransactionHandler <Event <TA> > { CurrentListener = bea.SampleNoTrans().Listen(@out.Node, trans1, h2, false) }; h1.Run = (trans2, ea) => trans2.Last( new Runnable { Run = () => { if (h1.CurrentListener != null) { h1.CurrentListener.Unlisten(); } h1.CurrentListener = ea.Listen(@out.Node, trans2, h2, true); } }); Listener l1 = bea.Updates().Listen(@out.Node, trans1, h1, false); return(@out.AddCleanup(l1)); }
/// ///Apply a value inside a behavior to a function inside a behavior. This is the ///primitive for all function lifting. /// public static Behavior <TB> Apply <TA, TB>(Behavior <Func <TA, TB> > bf, Behavior <TA> ba) { var @out = new EventSink <TB>(); var h = new Handler <Transaction> { Fired = false }; h.Run = trans1 => { if (h.Fired) { return; } h.Fired = true; trans1.Prioritized( @out.Node, new Handler <Transaction> { Run = trans2 => { @out.Send(trans2, bf.NewValue()(ba.NewValue())); h.Fired = false; } }); }; Listener l1 = bf.Updates().Listen_(@out.Node, new TransactionHandler <Func <TA, TB> > { Run = (trans1, f) => h.Run(trans1) }); Listener l2 = ba.Updates().Listen_(@out.Node, new TransactionHandler <TA> { Run = (trans1, a) => h.Run(trans1) }); return(@out.AddCleanup(l1).AddCleanup(l2).HoldLazy(() => bf.SampleNoTrans()(ba.SampleNoTrans()))); }