-3

How can the television channel problem as explained in this talk at 31th minute be solved by RX ?

The problem expressed in Rx is as follows:

The are two television channels (channel1 and channel2) which transmit a stream of images, plus a stream of fuzz which represents no channel or white noise.

There are two buttons which send events eButton1 and eButton2 when they are pressed.

These button presses should result in the respective channels being sent to the screen.

Each button press should be projected (mapped) into the respective channel, and then all channels combined into a selection stream as stream of streams which starts with the fuzz stream. Finally a switch operator sends the selected stream to the screen.

Question

What is the equivalent of Sodiums'switch and merge in RX?

Is it possible to solve it with pure higher order functions ? I.e. without using closures ? I don't see how that would be possible.

enter image description here

4

2 回答 2

8

SwitchMerge都存在于核心 Rx 库中,因此幻灯片中的代码实际上几乎逐字逐句地翻译成 Rx。

操作符在流的Switch流上工作——在 Rx 中这是一个类型IObservable<IObservable<T>>

Switch 扁平化这个流流,只发送最新的流到它的输出,所以你最终得到一个IObservable<T>.

请参阅下面的 C# 示例。我在演讲中尽可能地重用了变量名,所以这应该很容易理解。

唯一(非常轻微)不同的是hold函数被替换为 Rx 等效项StartWith

包括 nuget 包Rx-Main并将其作为控制台应用程序运行。代码订阅screen流并开始将帧从“Fuzz”通道渲染到控制台。它会提示您输入频道号。输入 1 或 2,您会看到输出切换到相应通道的帧。

// helper method to create channels
private static IObservable<string> CreateChannelStream(
    string name, CompositeDisposable disposables)
{
    // this hacks together a demo channel stream -
    // a stream of "frames" for the channel
    // for simplicity rather than using images, I use a string
    // message for each frame
    // how it works isn't important, just know you'll get a
    // message event every second
    var channel = Observable.Interval(TimeSpan.FromSeconds(1))
                            .Select(x => name + " Frame: " + x)
                            .Publish();
    disposables.Add(channel.Connect());
    return channel;
}

public static void Main()
{       
    // for cleaning up the hot channel streams
    var disposable = new CompositeDisposable();

    // some channels
    var fuzz = CreateChannelStream("Fuzz", disposable);
    var channel1 = CreateChannelStream("Channel1", disposable);
    var channel2 = CreateChannelStream("Channel2", disposable);

    // the button press event streams
    var eButton1 = new Subject<Unit>();
    var eButton2 = new Subject<Unit>();

    // the button presses are projected to
    // the respective channel streams
    // note, you could obtain the channel via a function call here
    // if you wanted to - to keep it close to the slides I'm not.
    var eChan1 = eButton1.Select(_ => channel1);
    var eChan2 = eButton2.Select(_ => channel2);

    // create the selection "stream of streams"
    // an IObservable<IObservable<string>> here
    // that starts with "fuzz"
    var sel = Observable.Merge(eChan1, eChan2).StartWith(fuzz);

    // flatten and select the most recent stream with Switch
    var screen = sel.Switch();

    // subscribe to the screen and print the frames
    // it will start with "fuzz"
    disposable.Add(screen.Subscribe(Console.WriteLine));

    bool quit = false;

    // a little test loop
    // entering 1 or 2 will switch
    // to that channel
    while(!quit)
    {
        var chan = Console.ReadLine();
        switch (chan.ToUpper())
        {
            case "1":
                // raise a button 1 event
                eButton1.OnNext(Unit.Default);
                break;
            case "2":
                // raise a button 2 event
                eButton2.OnNext(Unit.Default);
                break;  
            case "Q":
                quit = true;
                break;                
        }
    }         

    disposable.Dispose();
}
于 2015-01-26T23:36:50.550 回答
2

这是正确的事情吗:

IObservable<System.Drawing.Image> fuzz = ...
IObservable<System.Drawing.Image> channel1 = ...
IObservable<System.Drawing.Image> channel2 = ...

IObservable<string> eButton1 = ... // produces string "eButton1" when clicked
IObservable<string> eButton2 = ... // produces string "eButton2" when clicked

var output =
(
    from button in eButton1.Merge(eButton2).StartWith("")
    select
        button == "eButton1"
            ? channel1
            : (button == "eButton2"
                ? channel2 
                : fuzz)
).Switch();
于 2015-01-27T04:19:59.387 回答