我正在使用一个将结果作为双轨值(成功和失败)的库。在函数体Observable.map
中,我经常从函数的成功跟踪中获得可观察结果,我不知道如何处理它们(在Observable.map
体中)。
换句话说,我经常陷入结果如下所示的情况(当然这是最简单的):
Rop.Result<IObservable<Rop.Result<IObservable,Messages>,Messages>
一方面,将消息翻译回异常并引发它们对我来说似乎是连线的,另一方面,错误处理程序是不纯的函数,我宁愿不传递它们。
我想知道处理Observable.map
体双轨结果故障的标准和干净的解决方案是什么。
更新:示例
这是这个问题有史以来最简单的示例:
module problem
open FSharp.Control.Reactive
type Person = {FirstName:string;LastName:string}
let getPersonByLastName lastName =
let persons = Observable.toObservable<|seq{
yield {FirstName="Jhone";LastName="Smith"}
yield {FirstName="Joe";LastName="Smith"}
yield {FirstName="Jack";LastName="Smith"}
}
Rop.succeed persons
let main =
let final =
Observable.single("Smith")
|>Observable.map(fun lastName ->
let personResults = getPersonByLastName lastName
personResults
)
0
在这个例子中,表达式的final
结果是IObservable<Result<IObservable<Person>,ErrorMessage list>>
类型,但我希望它是IObservable<Person>
的,因为进一步的Observable
转换最终会得到非常肮脏和复杂的表达式。
在最简单的层面上,您需要的是一种提取然后显示包裹在RopResult
中的IObservable
的方法。解决方案的一部分已经在注释中提到(Observable.bind
),另一部分是函数RopResult<IObservable<'a>, 'b> -> IObservable<RopResult<'a,'b>>
。
为此,您需要解构RopResult
并处理这两种情况。因此,将其放在您陈述的问题的上下文中:
Observable.single("Smith")
|>Observable.bind(fun lastName ->
match getPersonByLastName lastName with
| Rop.RopResult.Success (next, msgs) ->
next |> Observable.map (fun x -> Rop.RopResult.Success (x, msgs))
| Rop.RopResult.Failure msgs ->
Observable.result <| Rop.RopResult.Failure msgs)
这是好代码吗?我不这么认为。您可以通过使用其他 ROP api 函数或在此处对绑定主体使用计算表达式来使其稍微好一点,但这不是重点。
使用可观察量的响应式编程和"面向铁路的编程"都是有用的工具,只要它们可以捕获和抽象出您正在建模的任何计算中涉及的一些复杂性元素。这是有效的,因为它们建立在可以很好地组合在一起的基元之上。当你试图像这样"交错"两者时,你会失去一些,因为你必须自己管理这些组合。
我想说你最好在这里使用异常 - 特别是因为可观察量对它们有内置的支持。
如果你不使用成功与消息,那么将Observable
和RopResult
结合起来似乎是很自然的。
exception ROPExn of string list
let combine = function
| Success (x, _) -> x
| Failure errors -> Observable.Throw(ROPExn(errors))
let main =
let final = Observable.single("Smith") |> Observable.bind(getPersonByLastName >> combine)
let handleError = function
|ROPExn(list) -> printfn "ROP fail"
| _ -> printfn "error"
let subscription = final |> Observable.subscribeWithCallbacks (fun p -> printfn "%s" p.FirstName) handleError ignore