0

Reactive Extensions で group by 関数を使用する方法を決定しようとしています。F# で使用されていることを説明する簡単な例を誰かが持っている可能性はありますか?

ありがとう!

4

1 に答える 1

4

あなたが直面している可能性が最も高い問題は、特に複数のオーバーロードを持つメソッドで、F# の型推論がラムダなどに関連する場合Func<T, T1...>に困難になることです。Action<T>

慣用的な C#/VB 用に設計された Rx の API を使用している場合、ほとんどの場合、型に注釈を付けてコンパイラを正しい方向に向ける必要があります。

最も単純な形式の GroupBy は、キー セレクターを取り込んで、グループのオブザーバブルを生成します。各グループにはキーがあり、それ自体がそのキーの下の値のストリームである Observable です。

この例では、偶数または奇数の 2 つのグループが形成されているため、2 つのグループを取得して、グループを再結合するためIGroupedObservable<string, int>SelectMany使用されます。

通常の Rx メソッドの使用:

let log message s = printfn "%s: %A" message s       

let disposable = 
    Observable.Interval(TimeSpan.FromSeconds(0.5))
              .Select(int)              
              .Do(log "Produced")
              .GroupBy(fun n -> if n % 2 = 0 then "Even" else "Odd")
              .SelectMany(fun (group : IGroupedObservable<string, int>) -> group.Select(fun i -> group.Key, i))          
              .Do(log "Kind")
              .Subscribe()              

これはかなり恐ろしいです...

より慣用的にするには、次のように Observable モジュールを拡張する必要があります。

type Observable with
    static member log message o = Observable.Do(o, log message)
    static member groupBy selector o = Observable.GroupBy(o, (fun v -> selector(v)))
    static member collect (selector : 'a -> IObservable<'b>) o = Observable.SelectMany(o, selector)

これで、上記と同じコードを次のように表現できます。

let disposable = 
    Observable.Interval(TimeSpan.FromSeconds(0.5))
    |> Observable.map int
    |> Observable.log "Produced"
    |> Observable.groupBy (fun n -> if n % 2 = 0 then "Even" else "Odd")
    |> Observable.collect(fun group -> group |> Observable.map(fun i -> group.Key, i))                  
    |> Observable.log "Kind"
    |> Observable.subscribe(fun _ -> ())

...これははるかに読みやすく、注釈は必要ありません。

出力:

Produced: 0
Kind: ("Even", 0)
Produced: 1
Kind: ("Odd", 1)
Produced: 2
Kind: ("Even", 2)
Produced: 3
Kind: ("Odd", 3)
于 2012-12-02T08:10:18.710 に答える