2

編集: Daniel と latkin が以下の回答とコメントで指摘したように、この質問には F# のバグが含まれており、2014 年初頭に修正されたようです。

Observable.StartWith のカリー化されたラッパーを作成しようとしています。プレリリースの Reactive Extensions 2.0 と VS11 ベータ版を使用しています。私の望む結果はstartWith : 'a -> IObservable<'a> -> IObservable<'a>. 明らかな実装は次のようになります。

let startWith 
        (value : 'a) 
        (observable : IObservable<'a>) 
        : IObservable<'a> =
    Observable.StartWith(observable, [| value |])

Observable.StartWith の意図したオーバーロードはStartWith<'TSource>(source : IObservable<'TSource>, params values: 'TSource[]) : IObservable<'TSource>.

コンパイラは紛らわしいエラーをスローします: This method expects a CLI 'params' parameter in this position. 'params' is a way of passing a variable number of arguments to a method in languages such as C#. Consider passing an array for this argument.

配列を渡していますまた、を省略して配列を渡さない[| |]ようにしましたが、これは一意の過負荷解決の失敗につながります。(おそらく、他のオーバーロードと一致する可能性があるため'aですSystem.Reactive.Concurrency.IScheduler。) F# 2.0/VS2010 も使用してみましたが、同じ結果が得られました。この種の状況やコンパイラ エラー メッセージに関するオンライン ディスカッションは見つかりませんでした。

これを実装する他の方法は考えられません。型パラメータが特定できる場合は問題ありません。たとえば、正常にlet prependZero : int -> IObservable<int> -> IObservable<int> = fun n o -> o.StartWith(n)動作します。しかし、一般的なバージョンがいいでしょう。

4

2 に答える 2

3

一般的なパラメータ配列を取り巻く型推論に問題があるようです。過負荷の解決を伴わない単純なケースでさえ、問題があります。

type A() = 
  static member M<'T>([<ParamArray>] args: 'T[]) = args

//None of these work
let m1 arg = A.M([|arg|])
let m2 args = A.M(args)
let m3<'T> (args:'T[]) = A.M<'T>(args)

非ジェネリックバージョンは機能します:

type B() = 
  static member M([<ParamArray>] args: obj[]) = args

//Both of these are okay
let m1 arg = B.M([|arg|])
let m2 args = B.M(args)

編集

私はfsbugsに電子メールを送りました、そして彼らはこれがバグであると答えました。ここに彼らが提案したいくつかの回避策があります。

let m1 arg = A.M<obj>([|arg|])
let m2 args = A.M<obj>(args)
let m3 (args:obj[]) = A.M<obj>(args)
let m4 (arg:obj) = A.M<obj>(arg)
let m5 arg1 arg2 = A.M<obj>(arg1,arg2)
let m6 (arg1:'T) = A.M<'T>(arg1)
let m7 (arg1:'T) (arg2:'T) = A.M<'T>(arg1,arg2)
let m8 (arg1:'T) (arg2:'T) = A.M(arg1,arg2)
let m9 (arg1:'T) = A.M(arg1)
let m10<'T> arg1 arg2 = A.M<'T>(arg1,arg2)
let m11<'T> (arg1:'T) (arg2:'T) = A.M<'T>(arg1,arg2)
于 2012-06-17T03:34:10.703 に答える
1

の最後の引数valueと一致させるために、シングルを単一要素配列にラップする必要はありません。スカラー値だけで問題ありません (これらのサンプルは理由を理解するのに役立つ場合があります)。ParamArrayObservable.StartWith

しかし、ジェネリック型のvalueは、 で利用可能な 2 つのオーバーロードの間にあいまいさを生み出しますObservable.StartWith。以下のように、2 引数のオーバーロードの暗黙的な型を引数リストに明示的に配置し、先頭に , を追加することで、 3引数のオーバーロードを強制することで、あいまいさを解消できます。ISchedulervalue

let startWith (value: 'a) observable =
    Observable.StartWith(observable, Scheduler.CurrentThread, value) 

これで、コードがコンパイルされて動作するはずです。簡単なチェックでこれを確認します。

Observable.Range(1,2)
|> startWith 10
|> fun x -> x.Subscribe(printf "%d ")

期待どおりに出力され10 1 2ます。

アップデート

Rx 2.0 ベータ版の場合、Schedulerリファレンスはわずかに異なりますが、残りの回答は変更されていません。

let startWith (value: 'a) (observable: IObservable<'a>) = 
    Observable.StartWith(observable, Concurrency.Scheduler.CurrentThread, value)
于 2012-06-17T04:35:56.983 に答える