过了一会儿,我在SO中翻阅了一些Rx代码并遇到了问题How to implement polling using Observables?。
从F#角度来看 是在F#parlor中使用(自定义)Either
类型或Choice。唉,我从很多层面开始都是错误的翻译,从类型开始。
但是,这可能会被用作更广泛的教育工具,而不仅仅是放弃尝试翻译。 有人可以借出一个功能强大的F#大脑并帮助翻译以下C#代码吗?
我使用了F#TaskBuilder
,但最近才发现它没有实现TryWith part of a computation builder中的TaskBuilder。因此,翻译第一段C#代码(或者可能应该转到async
路径)可能变得很困难,在源SO链接中提供的另一个版本没有使用异步结构。关于这个问题或运气不好,我也无法翻译。
我得到的错误是那种:
Type mismatch. Expecting a IScheduler -> CancellationToken -> Task but given a 'a * CancellationToken -> 'b The type 'IScheduler' does not match the type ''a * CancellationToken'
Type mismatch. Expecting a IObservable<Choice<'TResult,exn>> but given a
IObservable<'TResult> The resulting type would be infinite when unifying ''TResult' and 'Choice<'TResult,exn>'
等等。
-
[<Extension>]
type ObservableExtensions() =
static member inline poll<'TResult, 'TArg>(asyncFunction: 'TArg -> IObservable<'TResult>, parameterFactory: 'TArg, interval:TimeSpan, scheduler: IScheduler): IObservable<Choice<'TResult, exn>> =
Observable.Create<'TResult>(fun(observer:IObserver<'TResult>) ->
let task = new TaskBuilder()
let t(ctrl:IScheduler, ct:CancellationToken) = task {
while not <| ct.IsCancellationRequested do
try
let! result = asyncFunction(parameterFactory)
observer.OnNext(Choice1Of2(result))
with ex ->
observer.OnNext(Choice2Of2(ex))
do! ctrl.Sleep(interval, ct)
}
scheduler.ScheduleAsync(Func<IScheduler, CancellationToken, Task>(t)))
和相应的C#代码(1):
public IObservable<Either<Exception, TResult>> Poll<TResult, TArg>(
Func<TArg, IObservable<TResult>> asyncFunction,
Func<TArg> parameterFactory,
TimeSpan interval,
IScheduler scheduler)
{
return Observable.Create<Either<Exception, TResult>>(observer =>
{
return scheduler.ScheduleAsync(async (ctrl, ct) => {
while(!ct.IsCancellationRequested)
{
try
{
var result = await asyncFunction(parameterFactory());
observer.OnNext(Either.Right<Exception,TResult>(result));
}
catch(Exception ex)
{
observer.OnNext(Either.Left<Exception, TResult>(ex));
}
await ctrl.Sleep(interval, ct);
}
});
});
}
替代C#代码
public IObservable<Either<Exception, TResult>> Poll2<TResult, TArg>(
Func<TArg, IObservable<TResult>> asyncFunction,
Func<TArg> parameterFactory,
TimeSpan interval,
IScheduler scheduler)
{
return Observable.Create<Either<Exception, TResult>>(
observer =>
Observable.Defer(() => asyncFunction(parameterFactory()))
.Select(Either.Right<Exception, TResult>)
.Catch<Either<Exception, TResult>, Exception>(
ex => Observable.Return(Either.Left<Exception, TResult>(ex)))
.Concat(Observable.Defer(
() => Observable.Empty<Either<Exception, TResult>>()
.Delay(interval, scheduler)))
.Repeat().Subscribe(observer));
}
请注意,这与How to write a generic, recursive extension method in F#?有一些相似之处,因此与Write an Rx “RetryAfter” extension method extension method
相似&lt; edit:为了补充MisterMetaphor的优秀答案,我也会在这里添加一个没有间隔的版本。
type Observable with
static member Poll2(f: unit -> IObservable<_>, interval: TimeSpan, sched: IScheduler) : IObservable<_> =
Observable.Create<_>(fun observer ->
Observable.Defer(f)
.Select(Choice1Of2)
.Catch(Choice2Of2 >> Observable.Return)
.Concat(Observable.Defer(fun _ -> Observable.Empty().Delay(interval, sched)))
.Repeat()
.Subscribe(observer))
static member Poll2(f: 'a -> IObservable<_>, argFactory: unit -> 'a, interval: TimeSpan, sched: IScheduler) =
Observable.Poll2(argFactory >> f, interval, sched)
我不确定是否需要这样做,但是对于在here中发现的F#中的.Subscribe
(至少是Visual F#3.1.1.0)中的一个微妙错误的适当注释,更多here)。
答案 0 :(得分:2)
如果您不必使用Observable.Create
,则可以使用Observable.Interval
获得类似的结果:
type Observable with
static member Poll(f : unit -> IObservable<_>, interval : TimeSpan, sched : IScheduler) : IObservable<_> =
Observable.Interval(interval, sched)
.SelectMany(fun _ ->
Observable.Defer(f)
.Select(Choice1Of2)
.Catch(Choice2Of2 >> Observable.Return))
// An overload that matches your original function
static member Poll(f : 'a -> IObservable<_>, argFactory : unit -> 'a, interval : TimeSpan, sched : IScheduler) =
Observable.Poll(argFactory >> f, interval, sched)
我对此实现的喜欢是,您不必直接使用调度程序和Observable.Create
。我认为你应该总是使用现有的组合器/操作器,除非你绝对不得不这样做。
此外,Observable.Interval
使用SchedulePeriodic
(明显here),这可能比基于Task
的实施更有效和正确。