private static Cell <T> Calm <T>(Cell <T> a) { Lazy <T> initA = a.SampleLazy(); Lazy <IMaybe <T> > mInitA = initA.Map(Maybe.Just); return(Calm(Operational.Updates(a), mInitA).HoldLazy(initA)); }
public FrView(Window window, Fridget fr, IListener l) { StreamSink <MouseEvent> sMouse = new StreamSink <MouseEvent>(); StreamSink <KeyEvent> sKey = new StreamSink <KeyEvent>(); this.MouseDown += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); this.MouseUp += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); this.MouseMove += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); CellSink <IMaybe <Size> > size = new CellSink <IMaybe <Size> >(Maybe.Nothing <Size>()); this.SizeChanged += (sender, args) => size.Send(Maybe.Just(args.NewSize)); window.KeyDown += (sender, args) => { Key key = args.Key == Key.System ? args.SystemKey : args.Key; if (key == Key.Back) { sKey.Send(new BackspaceKeyEvent()); } }; window.TextInput += (sender, args) => sKey.Send(new StringKeyEvent(args.Text)); CellLoop <long> focus = new CellLoop <long>(); Fridget.Output fo = fr.Reify(size, sMouse, sKey, focus, new Supply()); focus.Loop(fo.SChangeFocus.Hold(-1)); this.drawable = fo.Drawable; this.l = new ImmutableCompositeListener(new[] { l, Operational.Updates(this.drawable).Listen(d => this.InvalidateVisual()) }); }
public void TestUpdates() { BehaviorSink <int> b = Behavior.CreateSink(9); List <int> @out = new List <int>(); IListener l = Operational.Updates(b).Listen(@out.Add); b.Send(2); b.Send(7); l.Unlisten(); CollectionAssert.AreEqual(new[] { 2, 7 }, @out); }
public void TestUpdates() { CellSink <int> c = Cell.CreateSink(9); List <int> @out = new List <int>(); IListener l = Operational.Updates(c).Listen(@out.Add); c.Send(2); c.Send(7); l.Unlisten(); CollectionAssert.AreEqual(new[] { 2, 7 }, @out); }
public void TestHoldUpdates() { StreamSink <int> s = Stream.CreateSink <int>(); DiscreteCell <int> c = s.Hold(0); List <int> @out = new List <int>(); IListener l = Operational.Updates(c.Cell).Listen(@out.Add); s.Send(2); s.Send(9); l.Unlisten(); CollectionAssert.AreEqual(new[] { 2, 9 }, @out); }
public void Test_Updates_TestCase() { Tuple <Stream <char>, Dictionary <int, Action> > st = MkStream(new Dictionary <int, char> { { 1, 'b' }, { 3, 'c' } }); Stream <char> s = st.Item1; Dictionary <int, Action> sf = st.Item2; DiscreteCell <char> c = s.Hold('a'); List <char> @out = RunSimulation <char>(Operational.Updates(c.Cell).Listen, new[] { sf }); CollectionAssert.AreEqual(new[] { 'b', 'c' }, @out); }
public void TestUpdates() { CellSink <int> c = new CellSink <int>(9); List <int> @out = new List <int>(); using (Operational.Updates(c).Listen(@out.Add)) { c.Send(2); c.Send(7); } CollectionAssert.AreEqual(new[] { 2, 7 }, @out); }
public void TestHoldUpdates() { StreamSink <int> s = new StreamSink <int>(); Cell <int> c = s.Hold(0); List <int> @out = new List <int>(); using (Operational.Updates(c).Listen(@out.Add)) { s.Send(2); s.Send(9); } CollectionAssert.AreEqual(new[] { 2, 9 }, @out); }
public SLabel(Cell <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.Sample())); // ReSharper disable once UseObjectOrCollectionInitializer List <IListener> listeners = new List <IListener>(); listeners.Add(Operational.Updates(text).Listen(setText)); this.listeners = listeners; }
public STextBox(Stream <string> setText, string initText, Cell <bool> enabled) { base.Text = initText; List <IListener> listeners = new List <IListener>(); StreamSink <int> sDecrement = new StreamSink <int>(); Cell <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); TextChangedEventHandler textChangedEventHandler = (sender, 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.Sample())); listeners.Add(setText.Listen(t => { this.Dispatcher.InvokeAsync(() => { this.TextChanged -= textChangedEventHandler; base.Text = t; this.TextChanged += textChangedEventHandler; sDecrement.Send(-1); }); })); listeners.Add(Operational.Updates(enabled).Listen(e => this.Dispatcher.InvokeIfNecessary(() => this.IsEnabled = e))); this.disposeListeners = () => { foreach (IListener l in listeners) { using (l) { } } }; }
public void FunctionalBehaviorLoop() { BehaviorSink <int> s = Behavior.CreateSink(0); Behavior <int> result = Behavior.Loop <int>().WithoutCaptures(l => Operational.Updates(s).Snapshot(l, (n, o) => n + o).Hold(0).AsBehavior()); List <int> @out = new List <int>(); using (Transaction.Run(() => Operational.Value(result).Listen(@out.Add))) { s.Send(1); s.Send(2); s.Send(3); } CollectionAssert.AreEqual(new[] { 0, 1, 3, 6 }, @out); }
public SButton(Cell <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.Sample()); // ReSharper disable once UseObjectOrCollectionInitializer List <IListener> listeners = new List <IListener>(); listeners.Add(Operational.Updates(enabled).Listen(e => this.Dispatcher.InvokeIfNecessary(() => this.IsEnabled = e))); this.listeners = listeners; }
public void TestMapWithSwitchC() { 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) }; CellSink <IReadOnlyList <Test> > v = Cell.CreateSink(list1); Cell <IReadOnlyList <int> > c = v.Map(oo => oo.Select(o => o.Value).Lift()).Map(o => o).SwitchC(); List <IReadOnlyList <int> > streamOutput = new List <IReadOnlyList <int> >(); IListener l = Operational.Updates(c).Listen(streamOutput.Add); List <IReadOnlyList <int> > cellOutput = new List <IReadOnlyList <int> >(); IListener l2 = Transaction.Run(() => Operational.Value(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]); }
public void ImperativeBehaviorLoop() { BehaviorSink <int> s = Behavior.CreateSink(0); Behavior <int> result = Transaction.Run( () => { BehaviorLoop <int> l = new BehaviorLoop <int>(); Behavior <int> resultLocal = Operational.Updates(s).Snapshot(l, (n, o) => n + o).Hold(0).AsBehavior(); l.Loop(resultLocal); return(resultLocal); }); List <int> @out = new List <int>(); using (Transaction.Run(() => Operational.Value(result).Listen(@out.Add))) { s.Send(1); s.Send(2); s.Send(3); } CollectionAssert.AreEqual(new[] { 0, 1, 3, 6 }, @out); }
public void ImperativeBehaviorLoopFailsWhenLoopedInSeparateTransaction() { InvalidOperationException actual = null; BehaviorLoop <int> l = null; new Thread( () => Transaction.RunVoid( () => { l = new BehaviorLoop <int>(); Thread.Sleep(500); })).Start(); try { BehaviorSink <int> s = Behavior.CreateSink(0); Transaction.RunVoid( () => { Thread.Sleep(250); Behavior <int> resultLocal = Operational.Updates(s).Snapshot(l, (n, o) => n + o).Hold(0).AsBehavior(); l.Loop(resultLocal); }); } catch (InvalidOperationException e) { actual = e; } Thread.Sleep(500); Assert.IsNotNull(actual); Assert.AreEqual("Loop must be looped in the same transaction that it was created in.", actual.Message); }
public void ImperativeBehaviorLoopFailsWhenLoopedTwice() { InvalidOperationException actual = null; try { BehaviorSink <int> s = Behavior.CreateSink(0); Transaction.RunVoid( () => { BehaviorLoop <int> l = new BehaviorLoop <int>(); Behavior <int> resultLocal = Operational.Updates(s).Snapshot(l, (n, o) => n + o).Hold(0).AsBehavior(); l.Loop(resultLocal); l.Loop(resultLocal); }); } catch (InvalidOperationException e) { actual = e; } Assert.IsNotNull(actual); Assert.AreEqual("Loop was looped more than once.", actual.Message); }
public void FunctionalBehaviorLoopWithCaptures() { BehaviorSink <int> s = Behavior.CreateSink(0); (Behavior <int> result, Behavior <int> s2) = Behavior.Loop <int>() .WithCaptures(l => (Behavior: Operational.Updates(s).Snapshot(l, (n, o) => n + o).Hold(0).AsBehavior(), Captures: s.Map(v => 2 * v))); List <int> @out = new List <int>(); List <int> out2 = new List <int>(); using (Transaction.Run(() => Operational.Value(result).Listen(@out.Add))) using (Transaction.Run(() => Operational.Value(s2).Listen(out2.Add))) { s.Send(1); s.Send(2); s.Send(3); } CollectionAssert.AreEqual(new[] { 0, 1, 3, 6 }, @out); CollectionAssert.AreEqual(new[] { 0, 2, 4, 6 }, out2); }
public static Cell <Signal> Integrate(Cell <Signal> sig, double initial) { Stream <Signal> sSig = Operational.Updates(sig); return(sSig.Accum(sig.Sample().Integrate(initial), (n, o) => n.Integrate(o.ValueAt(n.T0)))); }
public Implementation(PetrolPumpWindow petrolPump) { SComboBox <IPump> logic = new SComboBox <IPump>( new IPump[] { new LifeCyclePump(), new AccumulatePulsesPump(), new ShowDollarsPump(), new ClearSalePump(), new KeypadPump(), new PresetAmountPump() }, p => p.GetType().FullName); petrolPump.LogicComboBoxPlaceholder.Children.Add(logic); STextField textPrice1 = new STextField("2.149") { Width = 100 }; petrolPump.Price1Placeholder.Children.Add(textPrice1); STextField textPrice2 = new STextField("2.341") { Width = 100 }; petrolPump.Price2Placeholder.Children.Add(textPrice2); STextField textPrice3 = new STextField("1.499") { Width = 100 }; petrolPump.Price3Placeholder.Children.Add(textPrice3); Func <string, double> parseDoubleSafe = s => { double n; if (double.TryParse(s, out n)) { return(n); } return(0.0); }; StreamSink <Key> sKey = new StreamSink <Key>(); Dictionary <Key, FrameworkElement> containersByKey = new Dictionary <Key, FrameworkElement> { { Key.One, petrolPump.Keypad1Button }, { Key.Two, petrolPump.Keypad2Button }, { Key.Three, petrolPump.Keypad3Button }, { Key.Four, petrolPump.Keypad4Button }, { Key.Five, petrolPump.Keypad5Button }, { Key.Six, petrolPump.Keypad6Button }, { Key.Seven, petrolPump.Keypad7Button }, { Key.Eight, petrolPump.Keypad8Button }, { Key.Nine, petrolPump.Keypad9Button }, { Key.Zero, petrolPump.Keypad0Button }, { Key.Clear, petrolPump.KeypadClearButton } }; foreach (KeyValuePair <Key, FrameworkElement> containerAndKey in containersByKey) { containerAndKey.Value.MouseDown += async(sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => sKey.Send(containerAndKey.Key)); } }; } CellLoop <UpDown> nozzle1 = new CellLoop <UpDown>(); CellLoop <UpDown> nozzle2 = new CellLoop <UpDown>(); CellLoop <UpDown> nozzle3 = new CellLoop <UpDown>(); Cell <double> calibration = Cell.Constant(0.001); Cell <double> price1 = textPrice1.Text.Map(parseDoubleSafe); Cell <double> price2 = textPrice2.Text.Map(parseDoubleSafe); Cell <double> price3 = textPrice3.Text.Map(parseDoubleSafe); CellSink <Stream <Unit> > csClearSale = new CellSink <Stream <Unit> >(Sodium.Stream.Never <Unit>()); Stream <Unit> sClearSale = csClearSale.SwitchS(); StreamSink <int> sFuelPulses = new StreamSink <int>(); Cell <Outputs> outputs = logic.SelectedItem.Map( pump => pump.Create(new Inputs( Operational.Updates(nozzle1), Operational.Updates(nozzle2), Operational.Updates(nozzle3), sKey, sFuelPulses, calibration, price1, price2, price3, sClearSale))); Cell <Delivery> delivery = outputs.Map(o => o.Delivery).SwitchC(); Cell <string> presetLcd = outputs.Map(o => o.PresetLcd).SwitchC(); Cell <string> saleCostLcd = outputs.Map(o => o.SaleCostLcd).SwitchC(); Cell <string> saleQuantityLcd = outputs.Map(o => o.SaleQuantityLcd).SwitchC(); Cell <string> priceLcd1 = outputs.Map(o => o.PriceLcd1).SwitchC(); Cell <string> priceLcd2 = outputs.Map(o => o.PriceLcd2).SwitchC(); Cell <string> priceLcd3 = outputs.Map(o => o.PriceLcd3).SwitchC(); Stream <Unit> sBeep = outputs.Map(o => o.SBeep).SwitchS(); Stream <Sale> sSaleComplete = outputs.Map(o => o.SSaleComplete).SwitchS(); SoundPlayer beepPlayer = new SoundPlayer(GetResourceStream(@"sounds\beep.wav")); this.listeners.Add(sBeep.Listen(_ => new Thread(() => beepPlayer.PlaySync()) { IsBackground = true }.Start())); SoundPlayer fastRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\fast.wav")); Action stopFast = () => { }; Action playFast = () => { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { fastRumblePlayer.PlayLooping(); mre.WaitOne(); fastRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopFast = () => mre.Set(); }; SoundPlayer slowRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\slow.wav")); Action stopSlow = () => { }; Action playSlow = () => { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { slowRumblePlayer.PlayLooping(); mre.WaitOne(); slowRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopSlow = () => mre.Set(); }; this.listeners.Add(delivery.Changes().Listen(d => { petrolPump.Dispatcher.InvokeIfNecessary(() => { if (d == Delivery.Fast1 || d == Delivery.Fast2 || d == Delivery.Fast3) { playFast(); } else { stopFast(); } if (d == Delivery.Slow1 || d == Delivery.Slow2 || d == Delivery.Slow3) { playSlow(); } else { stopSlow(); } }); })); StackPanel presetLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.PresetPlaceholder.Children.Add(presetLcdStackPanel); this.listeners.Add(presetLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(presetLcdStackPanel, t, 5, true)))); StackPanel saleCostStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.DollarsPlaceholder.Children.Add(saleCostStackPanel); this.listeners.Add(saleCostLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleCostStackPanel, t, 5, true)))); StackPanel saleQuantityLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.LitersPlaceholder.Children.Add(saleQuantityLcdStackPanel); this.listeners.Add(saleQuantityLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleQuantityLcdStackPanel, t, 5, true)))); StackPanel priceLcd1StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel1Placeholder.Children.Add(priceLcd1StackPanel); this.listeners.Add(priceLcd1.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd1StackPanel, t, 5, false)))); StackPanel priceLcd2StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel2Placeholder.Children.Add(priceLcd2StackPanel); this.listeners.Add(priceLcd2.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd2StackPanel, t, 5, false)))); StackPanel priceLcd3StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel3Placeholder.Children.Add(priceLcd3StackPanel); this.listeners.Add(priceLcd3.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd3StackPanel, t, 5, false)))); Dictionary <CellLoop <UpDown>, Image> nozzles = new Dictionary <CellLoop <UpDown>, Image> { { nozzle1, petrolPump.Nozzle1Image }, { nozzle2, petrolPump.Nozzle2Image }, { nozzle3, petrolPump.Nozzle3Image } }; this.listeners.AddRange(nozzles.Select(nozzle => nozzle.Key.Listen(p => petrolPump.Dispatcher.InvokeIfNecessary(() => nozzle.Value.Margin = p == UpDown.Up ? new Thickness(0, 0, 0, 0) : new Thickness(0, 30, 0, 0))))); foreach (KeyValuePair <CellLoop <UpDown>, Image> nozzle in nozzles) { StreamSink <Unit> nozzleClicks = new StreamSink <Unit>(); nozzle.Value.MouseDown += async(sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => nozzleClicks.Send(Unit.Value)); } }; nozzle.Key.Loop(nozzleClicks.Snapshot(nozzle.Key, (_, n) => n == UpDown.Down ? UpDown.Up : UpDown.Down).Hold(UpDown.Down)); } this.listeners.Add(sSaleComplete.Listen(sale => { Task.Run(() => { petrolPump.Dispatcher.InvokeIfNecessary(() => { SaleCompleteDialog dialog = new SaleCompleteDialog( sale.Fuel.ToString(), Formatters.FormatPrice(sale.Price, null), Formatters.FormatSaleCost(sale.Cost), Formatters.FormatSaleQuantity(sale.Quantity)); dialog.Owner = petrolPump; csClearSale.Send(dialog.SOkClicked); dialog.Show(); IListener l = null; // ReSharper disable once RedundantAssignment l = dialog.SOkClicked.Listen(_ => { petrolPump.Dispatcher.InvokeIfNecessary(() => dialog.Close()); // ReSharper disable once AccessToModifiedClosure using (l) { } }); }); }); })); Task.Run(async() => { while (true) { Transaction.RunVoid(() => { switch (delivery.Sample()) { case Delivery.Fast1: case Delivery.Fast2: case Delivery.Fast3: sFuelPulses.Send(40); break; case Delivery.Slow1: case Delivery.Slow2: case Delivery.Slow3: sFuelPulses.Send(2); break; } }); await Task.Delay(200).ConfigureAwait(false); } // ReSharper disable once FunctionNeverReturns }); }