private FrButton(DiscreteCell <string> label, StreamLoop <Unit> sClicked) : base((size, sMouse, sKey, focus, idSupply) => { Stream <Unit> sPressed = sMouse.Snapshot(size, (e, mSize) => mSize.Match( s => { MouseButtonEventArgs b = e.Args as MouseButtonEventArgs; Point p = e.GetPosition(); return(b != null && b.ChangedButton == MouseButton.Left && b.ButtonState == MouseButtonState.Pressed && p.X >= 2 && p.X < s.Width - 2 && p.Y >= 2 && p.Y < s.Height - 2 ? Maybe.Just(Unit.Value) : Maybe.Nothing <Unit>()); }, Maybe.Nothing <Unit>)).FilterMaybe(); Stream <Unit> sReleased = sMouse.Snapshot(size, (e, mSize) => mSize.Match( s => { MouseButtonEventArgs b = e.Args as MouseButtonEventArgs; return(b != null && b.ChangedButton == MouseButton.Left && b.ButtonState == MouseButtonState.Released ? Maybe.Just(Unit.Value) : Maybe.Nothing <Unit>()); }, Maybe.Nothing <Unit>)).FilterMaybe(); DiscreteCell <bool> pressed = sPressed.MapTo(true).OrElse(sReleased.MapTo(false)).Hold(false); sClicked.Loop(sReleased.Gate(pressed)); Typeface typeface = new Typeface(new FontFamily("Helvetica"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal); DiscreteCell <Size> desiredSize = label.Map(l => { Size labelSize = FontUtilities.MeasureString(l, typeface, 13); return(new Size(labelSize.Width + 14, labelSize.Height + 10)); }); return(new Output( label.Lift( size, pressed, (l, mSize, p) => new DrawableDelegate(d => { mSize.Match(sz => { d.DrawRectangle(p ? Brushes.DarkGray : Brushes.LightGray, new Pen(Brushes.Black, 1), new Rect(new Point(2, 2), new Size(sz.Width - 5, sz.Height - 5))); FormattedText t = FontUtilities.GetStandardFormattedText(l, typeface, 13, Brushes.Black); d.DrawText(t, new Point((sz.Width - t.Width) / 2, (sz.Height - t.Height) / 2)); }, () => { }); })), desiredSize, Stream.Never <long>())); }) { this.SClicked = sClicked; }
public SLabel(DiscreteCell <string> text) { Action <string> setText = t => this.Dispatcher.InvokeIfNecessary(() => this.Text = t); // Set the initial value at the end of the transaction so it works with CellLoops. Transaction.Post(() => setText(text.Cell.Sample())); // ReSharper disable once UseObjectOrCollectionInitializer List <IListener> listeners = new List <IListener>(); listeners.Add(text.Updates.Listen(setText)); this.listeners = listeners; }
public void TestLiftSimultaneousUpdates() { List <int> @out = new List <int>(); DiscreteCellSink <int> cellSink = DiscreteCell.CreateSink(1); DiscreteCell <int> cell = cellSink.Map(v => 2 * v); IListener l = cellSink.Lift(cell, (x, y) => x + y).Updates.Listen(@out.Add); cellSink.Send(2); cellSink.Send(7); l.Unlisten(); CollectionAssert.AreEqual(new[] { 6, 21 }, @out); }
public void Post() { DiscreteCell <int> cell = Transaction.Run(() => { StreamSink <int> s = Stream.CreateSink <int>(); s.Send(2); return(s.Hold(1)); }); int value = 0; Transaction.Post(() => value = cell.Cell.Sample()); Assert.AreEqual(value, 2); }
public static DiscreteCell <double> Accumulate( Stream <Unit> sClearAccumulator, Stream <int> sPulses, DiscreteCell <double> calibration) { DiscreteCellLoop <int> total = new DiscreteCellLoop <int>(); total.Loop(sClearAccumulator.Map(u => 0) .OrElse(sPulses.Snapshot(total, (pulsesLocal, totalLocal) => pulsesLocal + totalLocal)) .Hold(0)); return(total.Lift( calibration, (totalLocal, calibrationLocal) => totalLocal * calibrationLocal)); }
public void TestDiscreteCellValuesThenLateListen() { DiscreteCellSink <int> c = DiscreteCell.CreateSink(9); List <int> @out = new List <int>(); Stream <int> value = c.Values; c.Send(8); IListener l = value.Listen(@out.Add); c.Send(2); c.Send(7); l.Unlisten(); CollectionAssert.AreEqual(new[] { 2, 7 }, @out); }
public SComboBox(Stream <IMaybe <T> > setSelectedItem, IMaybe <T> initSelectedItem, IEnumerable <T> items) { Action <IMaybe <T> > setSelectedItemImpl = m => base.SelectedItem = m.Match <object>(v => v, () => null); this.ItemsSource = items ?? new T[0]; setSelectedItemImpl(initSelectedItem); List <IListener> listeners = new List <IListener>(); StreamSink <int> sDecrement = new StreamSink <int>(); DiscreteCell <bool> allow = setSelectedItem.Map(_ => 1).OrElse(sDecrement).Accum(0, (b, d) => b + d).Map(b => b == 0); Func <IMaybe <T> > getSelectedItem = () => { object sel = base.SelectedItem; return(sel == null?Maybe.Nothing <T>() : Maybe.Just((T)sel)); }; StreamSink <IMaybe <T> > sUserSelectedItem = new StreamSink <IMaybe <T> >(); this.SUserSelectedItem = sUserSelectedItem; this.SelectedItem = sUserSelectedItem.Gate(allow).OrElse(setSelectedItem).Hold(initSelectedItem); SelectionChangedEventHandler selectionChangedEventHandler = (sender, args) => { IMaybe <T> selectedItem = getSelectedItem(); this.Dispatcher.InvokeAsync(() => sUserSelectedItem.Send(selectedItem)); }; this.SelectionChanged += selectionChangedEventHandler; listeners.Add(setSelectedItem.Listen(m => { this.Dispatcher.InvokeAsync(() => { this.SelectionChanged -= selectionChangedEventHandler; setSelectedItemImpl(m); this.SelectionChanged += selectionChangedEventHandler; sDecrement.Send(-1); }); })); this.disposeListeners = () => { foreach (IListener l in listeners) { l.Unlisten(); } }; }
public static DiscreteCell <double> CapturePrice( Stream <Fuel> sStart, DiscreteCell <double> price1, DiscreteCell <double> price2, DiscreteCell <double> price3) { Stream <double> sPrice1 = sStart.Snapshot(price1, (f, p) => f == Fuel.One ? Maybe.Some(p) : Maybe.None).FilterMaybe(); Stream <double> sPrice2 = sStart.Snapshot(price2, (f, p) => f == Fuel.Two ? Maybe.Some(p) : Maybe.None).FilterMaybe(); Stream <double> sPrice3 = sStart.Snapshot(price3, (f, p) => f == Fuel.Three ? Maybe.Some(p) : Maybe.None).FilterMaybe(); return(sPrice1.OrElse(sPrice2.OrElse(sPrice3)).Hold(0.0)); }
public void TestAccum() { StreamSink <int> sa = Stream.CreateSink <int>(); List <int> @out = new List <int>(); DiscreteCell <int> sum = sa.Accum(100, (a, s) => a + s); IListener l = sum.Listen(@out.Add); sa.Send(5); sa.Send(7); sa.Send(1); sa.Send(2); sa.Send(3); l.Unlisten(); CollectionAssert.AreEqual(new[] { 100, 105, 112, 113, 115, 118 }, @out); }
public MainWindow() { this.InitializeComponent(); this.Container.Children.Add(Transaction.Run(() => { FrButton ok = new FrButton(DiscreteCell.Constant("OK")); FrButton cancel = new FrButton(DiscreteCell.Constant("Cancel")); IReadOnlyList <Fridget> fridgets = new[] { ok, cancel }; Fridget dialog = new FrFlow(Orientation.Horizontal, fridgets); IListener lOk = ok.SClicked.Listen(_ => this.AddMessage("OK")); IListener lCancel = cancel.SClicked.Listen(_ => this.AddMessage("Cancel")); return(new FrView(this, dialog, new CompositeListener(new[] { lOk, lCancel }))); })); }
public void TestCalm2() { DiscreteCellSink <int> c = DiscreteCell.CreateSink(2); List <int> @out = new List <int>(); IListener l = Transaction.Run(() => c.Calm().Listen(@out.Add)); c.Send(4); c.Send(2); c.Send(4); c.Send(4); c.Send(2); c.Send(2); l.Unlisten(); CollectionAssert.AreEqual(new[] { 2, 4, 2, 4, 2 }, @out); }
public void PostInTransaction() { int value = 0; Transaction.RunVoid(() => { StreamSink <int> s = Stream.CreateSink <int>(); s.Send(2); DiscreteCell <int> c = s.Hold(1); Transaction.Post(() => value = c.Cell.Sample()); Assert.AreEqual(value, 0); }); Assert.AreEqual(value, 2); }
public MainWindow() { this.InitializeComponent(); SDateField dep = new SDateField(); SDateField ret = new SDateField(); DiscreteCell <bool> valid = dep.SelectedDate.Lift(ret.SelectedDate, (d, r) => d <= r); SButton ok = new SButton(valid) { Content = "OK", Width = 75 }; this.DeparturePlaceholder.Children.Add(dep); this.ReturnPlaceholder.Children.Add(ret); this.ButtonPlaceholder.Children.Add(ok); }
public SButton(DiscreteCell <bool> enabled) { StreamSink <Unit> sClickedSink = new StreamSink <Unit>(); this.SClicked = sClickedSink; this.Click += (sender, args) => sClickedSink.Send(Unit.Value); // Set the initial value at the end of the transaction so it works with CellLoops. Transaction.Post(() => this.IsEnabled = enabled.Cell.Sample()); // ReSharper disable once UseObjectOrCollectionInitializer List <IListener> listeners = new List <IListener>(); listeners.Add(enabled.Updates.Listen(e => this.Dispatcher.InvokeIfNecessary(() => this.IsEnabled = e))); this.listeners = listeners; }
public STextBox(Stream <string> setText, string initText, DiscreteCell <bool> enabled) { base.Text = initText; List <IListener> listeners = new List <IListener>(); StreamSink <int> sDecrement = new StreamSink <int>(); DiscreteCell <bool> allow = setText.Map(_ => 1).OrElse(sDecrement).Accum(0, (b, d) => b + d).Map(b => b == 0); StreamSink <string> sUserChanges = new StreamSink <string>(); this.SUserChanges = sUserChanges; this.Text = sUserChanges.Gate(allow).OrElse(setText).Hold(initText); void TextChangedEventHandler(object sender, TextChangedEventArgs args) { string text = base.Text; this.Dispatcher.InvokeAsync(() => sUserChanges.Send(text)); } this.TextChanged += TextChangedEventHandler; // Set the initial value at the end of the transaction so it works with CellLoops. Transaction.Post(() => this.Dispatcher.InvokeIfNecessary(() => this.IsEnabled = enabled.Cell.Sample())); listeners.Add(setText.Listen(t => { this.Dispatcher.InvokeAsync(() => { this.TextChanged -= TextChangedEventHandler; base.Text = t; this.TextChanged += TextChangedEventHandler; sDecrement.Send(-1); }); })); listeners.Add(enabled.Updates.Listen(e => this.Dispatcher.InvokeIfNecessary(() => this.IsEnabled = e))); this.disposeListeners = () => { foreach (IListener l in listeners) { l.Unlisten(); } }; }
public Frp(Action <string> addMessage) { this.listener = Transaction.Run(() => { DiscreteCell <Maybe <DragInfo> > dragInfo = this.sMouseDown.Map(me => Maybe.Some(new DragInfo(me, Canvas.GetLeft(me.Element.Polygon).ZeroIfNaN(), Canvas.GetTop(me.Element.Polygon).ZeroIfNaN()))) .OrElse(this.sMouseUp.Map(_ => Maybe <DragInfo> .None)).Hold(Maybe.None); Stream <MouseEvt> mouseMoveWhileDragging = dragInfo.Map(md => md.Match(d => this.sMouseMove, Stream.Never <MouseEvt>)).SwitchS(); IListener listener1 = dragInfo.Values.FilterMaybe().Listen(d => addMessage("FRP dragging " + d.Me.Element.Name)); IListener listener2 = mouseMoveWhileDragging.Snapshot(dragInfo, (me, md) => md.Match(d => Maybe.Some(new Reposition(d, me)), () => Maybe.None)).FilterMaybe().Listen(p => { Canvas.SetLeft(p.Polygon, p.Left); Canvas.SetTop(p.Polygon, p.Top); }); return(new CompositeListener(new[] { listener1, listener2 })); }); }
public MainWindow() { this.InitializeComponent(); STextBox english = new STextBox("I like FRP") { Width = 150 }; this.TextBoxPlaceholder.Children.Add(english); Stream <string> sLatin = this.TranslateButton.SClicked.Snapshot(english.Text, (u, t) => Regex.Replace(t.Trim(), " |$", "us ")); DiscreteCell <string> latin = sLatin.Hold(string.Empty); SLabel lblLatin = new SLabel(latin); this.TextPlaceholder.Children.Add(lblLatin); }
public void Test_Snapshot_TestCase() { Tuple <Stream <char>, Dictionary <int, Action> > s1T = MkStream(new Dictionary <int, char> { { 0, 'a' }, { 3, 'b' }, { 5, 'c' } }); Stream <char> s1 = s1T.Item1; Dictionary <int, Action> s1F = s1T.Item2; Tuple <Stream <int>, Dictionary <int, Action> > s2T = MkStream(new Dictionary <int, int> { { 1, 4 }, { 5, 7 } }); Stream <int> s2 = s2T.Item1; Dictionary <int, Action> s2F = s2T.Item2; DiscreteCell <int> c = s2.Hold(3); List <int> @out = RunSimulation <int>(s1.Snapshot(c.Cell).Listen, new[] { s1F, s2F }); CollectionAssert.AreEqual(new[] { 3, 4, 4 }, @out); }
public void TestLiftFromSimultaneous() { ValueTuple <DiscreteCellSink <int>, DiscreteCellSink <int> > t = Transaction.Run(() => { DiscreteCellSink <int> localC1 = DiscreteCell.CreateSink(3); DiscreteCellSink <int> localC2 = DiscreteCell.CreateSink(5); localC2.Send(7); return(ValueTuple.Create(localC1, localC2)); }); DiscreteCellSink <int> c1 = t.Item1; DiscreteCellSink <int> c2 = t.Item2; List <int> @out = new List <int>(); IListener l = c1.Lift(c2, (x, y) => x + y).Listen(@out.Add); l.Unlisten(); CollectionAssert.AreEqual(new[] { 10 }, @out); }
public MainWindow() { this.InitializeComponent(); STextBox msg = new STextBox("Hello") { Width = 150 }; DiscreteCell <string> reversed = msg.Text.Map(t => new string(t.Reverse().ToArray())); SLabel lbl = new SLabel(reversed) { Width = 150, Margin = new Thickness(5, 0, 0, 0) }; this.Container.Children.Add(msg); this.Container.Children.Add(lbl); }
public void TestDiscreteCellValuesThenMerge() { DiscreteCellSink <int> c1 = DiscreteCell.CreateSink(9); DiscreteCellSink <int> c2 = DiscreteCell.CreateSink(2); List <int> @out = new List <int>(); IListener l = Transaction.Run(() => c1.Values.Merge(c2.Values, (x, y) => x + y).Listen(@out.Add)); c1.Send(1); c2.Send(4); Transaction.RunVoid(() => { c1.Send(7); c2.Send(5); }); l.Unlisten(); CollectionAssert.AreEqual(new[] { 11, 1, 4, 12 }, @out); }
public void Test_Apply_TestCase() { Tuple <Stream <int>, Dictionary <int, Action> > s1T = MkStream(new Dictionary <int, int> { { 1, 200 }, { 2, 300 }, { 4, 400 } }); Stream <int> s1 = s1T.Item1; Dictionary <int, Action> s1F = s1T.Item2; DiscreteCell <int> ca = s1.Hold(100); Tuple <Stream <Func <int, int> >, Dictionary <int, Action> > s2T = MkStream(new Dictionary <int, Func <int, int> > { { 1, x => x + 5 }, { 3, x => x + 6 } }); Stream <Func <int, int> > s2 = s2T.Item1; Dictionary <int, Action> s2F = s2T.Item2; DiscreteCell <Func <int, int> > cf = s2.Hold(x => x + 0); List <int> @out = RunSimulation <int>(ca.Apply(cf).Listen, new[] { s1F, s2F }); CollectionAssert.AreEqual(new[] { 100, 205, 305, 306, 406 }, @out); }
public MainWindow() { this.InitializeComponent(); this.Container.Children.Add(Transaction.Run(() => { FrTextField firstName = new FrTextField("Joe"); FrTextField lastName = new FrTextField("Bloggs"); FrButton ok = new FrButton(DiscreteCell.Constant("OK")); FrButton cancel = new FrButton(DiscreteCell.Constant("Cancel")); IReadOnlyList <Fridget> buttons = new[] { ok, cancel }; Fridget buttonPanel = new FrFlow(Orientation.Horizontal, buttons); IReadOnlyList <Fridget> fridgets = new[] { buttonPanel, firstName, lastName }; Fridget dialog = new FrFlow(Orientation.Vertical, fridgets); IListener lOk = ok.SClicked.Snapshot(firstName.Text, lastName.Text, (_, f, l) => f + " " + l).Listen(n => this.AddMessage("OK: " + n)); IListener lCancel = cancel.SClicked.Listen(_ => this.AddMessage("Cancel")); return(new FrView(this, dialog, new CompositeListener(new[] { lOk, lCancel }))); })); }
public void TestLiftListLarge() { IReadOnlyList <DiscreteCellSink <int> > cellSinks = Enumerable.Range(0, 500).Select(_ => DiscreteCell.CreateSink(1)).ToArray(); DiscreteCell <int> sum = cellSinks.Lift().Map(v => v.Sum()); List <int> @out = new List <int>(); IListener l = sum.Listen(@out.Add); cellSinks[4].Send(5); cellSinks[5].Send(5); Transaction.RunVoid(() => { cellSinks[9].Send(5); cellSinks[17].Send(5); cellSinks[41].Send(5); cellSinks[48].Send(5); }); l.Unlisten(); CollectionAssert.AreEqual(new[] { 500, 504, 508, 524 }, @out); }
public void TestLiftInSwitchC() { IReadOnlyList <Test> list1 = new[] { new Test(0), new Test(1), new Test(2), new Test(3), new Test(4) }; IReadOnlyList <Test> list2 = new[] { new Test(5), new Test(6), new Test(7), new Test(8), new Test(9) }; DiscreteCellSink <IReadOnlyList <Test> > v = DiscreteCell.CreateSink(list1); DiscreteCell <IReadOnlyList <int> > c = v.Map(oo => oo.Select(o => o.Value).Lift()).SwitchC(); List <IReadOnlyList <int> > streamOutput = new List <IReadOnlyList <int> >(); IListener l = c.Updates.Listen(streamOutput.Add); List <IReadOnlyList <int> > cellOutput = new List <IReadOnlyList <int> >(); IListener l2 = c.Listen(cellOutput.Add); list1[2].Value.Send(12); list2[1].Value.Send(16); list1[4].Value.Send(14); Transaction.RunVoid(() => { list2[2].Value.Send(17); list1[0].Value.Send(10); v.Send(list2); }); list1[3].Value.Send(13); list2[3].Value.Send(18); l2.Unlisten(); l.Unlisten(); Assert.AreEqual(4, streamOutput.Count); Assert.AreEqual(5, cellOutput.Count); CollectionAssert.AreEqual(new[] { 0, 1, 2, 3, 4 }, cellOutput[0]); CollectionAssert.AreEqual(new[] { 0, 1, 12, 3, 4 }, streamOutput[0]); CollectionAssert.AreEqual(new[] { 0, 1, 12, 3, 4 }, cellOutput[1]); CollectionAssert.AreEqual(new[] { 0, 1, 12, 3, 14 }, streamOutput[1]); CollectionAssert.AreEqual(new[] { 0, 1, 12, 3, 14 }, cellOutput[2]); CollectionAssert.AreEqual(new[] { 5, 16, 17, 8, 9 }, streamOutput[2]); CollectionAssert.AreEqual(new[] { 5, 16, 17, 8, 9 }, cellOutput[3]); CollectionAssert.AreEqual(new[] { 5, 16, 17, 18, 9 }, streamOutput[3]); CollectionAssert.AreEqual(new[] { 5, 16, 17, 18, 9 }, cellOutput[4]); }
private FrButton(DiscreteCell <string> label, StreamLoop <Unit> sClicked) : base((size, sMouse, sKey, focus, idSupply) => { Stream <Unit> sPressed = sMouse.Snapshot(size, (e, mSize) => mSize.Bind( s => { MouseButtonEventArgs b = e.Args as MouseButtonEventArgs; Point p = e.GetPosition(); return(b != null && b.ChangedButton == MouseButton.Left && b.ButtonState == MouseButtonState.Pressed && p.X >= 2 && p.X < s.Width - 2 && p.Y >= 2 && p.Y < s.Height - 2 ? Maybe.Some(Unit.Value) : Maybe.None); })).FilterMaybe(); Stream <Unit> sReleased = sMouse.Snapshot(size, (e, mSize) => mSize.Bind( s => e.Args is MouseButtonEventArgs b && b.ChangedButton == MouseButton.Left && b.ButtonState == MouseButtonState.Released ? Maybe.Some(Unit.Value) : Maybe.None)).FilterMaybe();
public void Run() { DiscreteCellSink <double> mainClock = new DiscreteCellSink <double>(0.0); StreamSink <Unit> sPause = new StreamSink <Unit>(); StreamSink <Unit> sResume = new StreamSink <Unit>(); DiscreteCell <double> gameClock = PausableClock(sPause, sResume, mainClock); IListener l = mainClock.Lift(gameClock, (m, g) => "main=" + m + " game=" + g).Listen(Console.WriteLine); mainClock.Send(1.0); mainClock.Send(2.0); mainClock.Send(3.0); sPause.Send(Unit.Value); mainClock.Send(4.0); mainClock.Send(5.0); mainClock.Send(6.0); sResume.Send(Unit.Value); mainClock.Send(7.0); l.Unlisten(); }
public Outputs Create(Inputs inputs) { LifeCycle lc = new LifeCycle(inputs.SNozzle1, inputs.SNozzle2, inputs.SNozzle3); DiscreteCell <double> litersDelivered = Accumulate(lc.SStart.Map(_ => Unit.Value), inputs.SFuelPulses, inputs.Calibration); return(new Outputs() .SetDelivery(lc.FillActive.Map( m => m.Equals(Maybe.Just(Fuel.One)) ? Delivery.Fast1 : m.Equals(Maybe.Just(Fuel.Two)) ? Delivery.Fast2 : m.Equals(Maybe.Just(Fuel.Three)) ? Delivery.Fast3 : Delivery.Off)) .SetSaleQuantityLcd(litersDelivered.Map(Formatters.FormatSaleQuantity))); }
public MainWindow() { this.InitializeComponent(); SDateField dep = new SDateField(); SDateField ret = new SDateField(); Rule r1 = new Rule((d, r) => d <= r); Rule r2 = new Rule((d, r) => !Unlucky(d) && !Unlucky(r)); Rule rule = r1.And(r2); DiscreteCell <bool> valid = rule.Reify(dep.SelectedDate, ret.SelectedDate); SButton ok = new SButton(valid) { Content = "OK", Width = 75 }; this.DeparturePlaceholder.Children.Add(dep); this.ReturnPlaceholder.Children.Add(ret); this.ButtonPlaceholder.Children.Add(ok); }
public void PostInNestedConstructTransaction() { int value = 0; Transaction.RunConstruct(() => { StreamSink <int> s = Stream.CreateSink <int>(); s.Send(2); Transaction.RunVoid(() => { DiscreteCell <int> c = s.Hold(1); Transaction.Post(() => value = c.Cell.Sample()); }); Assert.AreEqual(value, 0); return(Unit.Value); }); Assert.AreEqual(value, 2); }