Edit :请注意,正如丹尼尔和拉特金在下面的答案和评论中指出的那样,这个问题涉及F#中的一个错误,似乎已经在2014年初修复了 .
我'm trying to write a curried wrapper for Observable.StartWith. I'm使用预发布Reactive Extensions 2.0和VS11 beta . 我想要的结果是 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,它给出了相同的结果 . 我找不到任何关于此类情况或编译器错误消息的在线讨论 .
我可以't think of any other way to implement this. Note that in cases where the type parameter can be determined, it'不是问题 . 例如, let prependZero : int -> IObservable<int> -> IObservable<int> = fun n o -> o.StartWith(n)
工作正常 . 但通用版本会很好 .
2 回答
它看起来像围绕通用param数组的类型推断的问题 . 即使是一个不涉及重载解析的简单案例也存在问题:
非通用版本有效:
编辑
我通过电子邮件发送了fsbugs,他们回复说这是一个错误 . 以下是他们建议的一些解决方法 .
您不需要将单个
value
包装成单个元素数组,以使其与Observable.StartWith
的最后ParamArray
参数匹配,只需标量值即可(these samples可能有助于理解原因) .但是
value
的泛型类型会在Observable.StartWith
的两个可用重载之间产生歧义 . 可以通过强制three-agrument overload来实现消歧,方法是将两个参数重载的隐式类型IScheduler
显式地放到参数列表中,前面加上value
,如下所示:现在你的代码应该编译和工作 . 快速检查确认了这一点:
按预期输出
10 1 2
.Update
对于Rx 2.0 beta,
Scheduler
引用会略有不同,其余答案保持不变: