Calling a generic function with parameters from F # (Observable.StartWith)

Change Please note that, as Daniel and Latin noted in the answer and comment below, this question is related to an error in F #, which seems to have been fixed in early 2014.

I am trying to write a curry wrapper for Observable.StartWith. I am using Prerelease Reactive Extensions 2.0 and the beta version of VS11. My desired result would be startWith : 'a -> IObservable<'a> -> IObservable<'a> . An obvious implementation would be something like this:

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

Estimated Overload Observable.StartWith StartWith<'TSource>(source : IObservable<'TSource>, params values: 'TSource[]) : IObservable<'TSource> .

The compiler creates a confusing error: 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 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 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 .

I am passing an array. I also tried not to pass the array, omitting [| |] [| |] , which results in a unique overload error. (Presumably due to the possibility that 'a could be System.Reactive.Concurrency.IScheduler by mapping another overload.) I also tried using F # 2.0 / VS2010, which gives the same result. I could not find any online discussion of these kinds of situations or compiler error messages.

I can't think of another way to implement this. Note that in cases where a type parameter can be specified, this is not a problem. For example, let prependZero : int -> IObservable<int> -> IObservable<int> = fun no -> o.StartWith(n) works fine. But the general version would be nice.

+2
source share
2 answers

There seems to be a problem with type inference around shared param arrays. Even a simple case not related to overload resolution has problems:

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

Non-generic versions work:

 type B() = static member M([<ParamArray>] args: obj[]) = args //Both of these are okay let m1 arg = BM([|arg|]) let m2 args = BM(args) 

EDIT

I emailed fsbugs and they replied that it was a mistake. Here are some ways to solve them.

 let m1 arg = AM<obj>([|arg|]) let m2 args = AM<obj>(args) let m3 (args:obj[]) = AM<obj>(args) let m4 (arg:obj) = AM<obj>(arg) let m5 arg1 arg2 = AM<obj>(arg1,arg2) let m6 (arg1:'T) = AM<'T>(arg1) let m7 (arg1:'T) (arg2:'T) = AM<'T>(arg1,arg2) let m8 (arg1:'T) (arg2:'T) = AM(arg1,arg2) let m9 (arg1:'T) = AM(arg1) let m10<'T> arg1 arg2 = AM<'T>(arg1,arg2) let m11<'T> (arg1:'T) (arg2:'T) = AM<'T>(arg1,arg2) 
+3
source

You do not need to wrap your single value in a single array of elements to match the last argument of ParamArray Observable.StartWith , just a scalar value in order ( these patterns can help to understand why).

But then the generic value type creates an ambiguity between the two available overloads for Observable.StartWith . Mismatch can be achieved by forcing a three-stage overload by explicitly placing the implicit IScheduler type from the two-argument overload in the list argument by adding value , as shown below:

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

Your code should now compile and work. A quick check confirms this:

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

output as expected 10 1 2 .

Update

For Rx 2.0 beta, the Scheduler link will be slightly different, the rest of the answer remains unchanged:

 let startWith (value: 'a) (observable: IObservable<'a>) = Observable.StartWith(observable, Concurrency.Scheduler.CurrentThread, value) 
+1
source

All Articles