2017-03-24 13 views
4

私はこのように動作するRxコンポーネントをテストするためのツールを用意しています:'v seqとキーセレクタ関数(keySelector :: 'v -> 'k)で指定されたイベントの順序が与えられたら、groupped observablesが保証されていることを保証するMap<'k, IObservable<'k>>を作成します。上記の列挙によって定義されるグローバル順序の値。オブザーバブル間の依存関係を作成する方法は?

例えば

open System 
open System.Reactive.Linq 
open FSharp.Control.Reactive 

let subscribeAfter (o1: IObservable<'a>) (o2 : IObservable<'b>) : IObservable<'b> = 
    fun (observer : IObserver<'b>) -> 
     let tempObserver = { new IObserver<'a> with 
           member this.OnNext x =() 
           member this.OnError e = observer.OnError e 
           member this.OnCompleted() = o2 |> Observable.subscribeObserver observer |> ignore 
          } 
     o1.Subscribe tempObserver 
    |> Observable.Create 

let makeObservables (keySelector : 'a -> 'k) (xs : 'a seq) : Map<'k, IObservable<'a>> = 
    let makeDependencies : ('k * IObservable<'a>) seq -> ('k * IObservable<'a>) seq = 
     let makeDep ((_, o1), (k2, o2)) = (k2, subscribeAfter o1 o2) 

     Seq.pairwise 
     >> Seq.map makeDep 

    let makeObservable x = (keySelector x, Observable.single x) 

    let firstItem = 
     Seq.head xs 
     |> makeObservable 
     |> Seq.singleton 

    let dependentObservables = 
     xs 
     |> Seq.map makeObservable 
     |> makeDependencies 

    dependentObservables 
    |> Seq.append firstItem 
    |> Seq.groupBy fst 
    |> Seq.map (fun (k, obs) -> (k, obs |> Seq.map snd |> Observable.concatSeq)) 
    |> Map.ofSeq 

[<EntryPoint>] 
let main argv = 
    let isEven x = (x % 2 = 0) 

    let splits : Map<bool, IObservable<int>> = 
     [1;2;3;4;5] 
     |> makeObservables isEven 

    use subscription = 
     splits 
     |> Map.toSeq 
     |> Seq.map snd 
     |> Observable.mergeSeq 
     |> Observable.subscribe (printfn "%A") 


    Console.ReadKey() |> ignore 
    0 // return an integer exit code 

を...しかし、結果は予想と観測されていないよう: makeObservables isEven [1;2;3;4;5;6] ...これは私の試みです

{ true : -2-4-6|, 
    false: 1-3-5| } 

生成しなければならないが、このようになります。値はグローバルオーダーではありません。

どうやら、各グループ内の項目が正しく降伏しているが、グループは、そのより連結のようにマージされているときに、マージ

が予想される出力は次のようになります。1 2 3 4 5 ...しかし、実際の出力は1 3 5 2 4

です

私は間違って何をしていますか?

ありがとうございます!

答えて

2

あなたはこの欠けて説明します。

{ true : -2-4-6|, 
    false: 1-3-5| } 

しかし、あなたが本当にこれを作成している:

{ true : 246|, 
    false: 135| } 

観測内の項目間の時間ギャップがありませんので、mergeは基本的に一定のレースを持っているが調子。 Rxは、与えられたシーケンスの要素1が要素2の前に起動することを保証しますが、Mergeは、このような場合を保証しません。

Mergeを元の順序で再配列できるようにするには、観測値に時間差を導入する必要があります。

+0

タイムギャップはありませんが、subscribeAfterは、最初のパラメータが完了した後にのみ利回りの観測値を生成する必要があります。注文を保証するべきではありませんか? – vidi

+0

F#は私の最高の言語ではありませんが、私が間違って読んでいない限り、 'subscribeAfter'は基本的に1が3の前にくることを保証しています。 2が3の前に来るわけではありません。私が知る限り、あなたは 'Concat'を再実装しています。 – Shlomo

+0

さらに根本的に、従属所見の概念は実際にはありません。 Join、GroupJoin、Zip、And/Then/Whenなど。 – Shlomo

関連する問題